thorxmlwrite.cpp 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "platform.h"
  14. #include "jlib.hpp"
  15. #include "thorxmlwrite.hpp"
  16. #include "eclrtl.hpp"
  17. #include "rtlkey.hpp"
  18. #include "eclhelper.hpp"
  19. #include "deftype.hpp"
  20. #include "rtlbcd.hpp"
  21. CommonXmlWriter::CommonXmlWriter(unsigned _flags, unsigned initialIndent, IXmlStreamFlusher *_flusher)
  22. {
  23. flusher = _flusher;
  24. flags = _flags;
  25. indent = initialIndent;
  26. nestLimit = flags & XWFnoindent ? (unsigned) -1 : 0;
  27. tagClosed = true;
  28. }
  29. CommonXmlWriter::~CommonXmlWriter()
  30. {
  31. flush(true);
  32. }
  33. IXmlWriterExt & CommonXmlWriter::clear()
  34. {
  35. out.clear();
  36. indent = 0;
  37. nestLimit = flags & XWFnoindent ? (unsigned) -1 : 0;
  38. tagClosed = true;
  39. return *this;
  40. }
  41. bool CommonXmlWriter::checkForAttribute(const char * fieldname)
  42. {
  43. if (!tagClosed)
  44. {
  45. if (fieldname && (fieldname[0] == '@'))
  46. return true;
  47. closeTag();
  48. }
  49. return false;
  50. }
  51. void CommonXmlWriter::closeTag()
  52. {
  53. if (!tagClosed)
  54. {
  55. out.append(">");
  56. if (!nestLimit)
  57. out.newline();
  58. tagClosed = true;
  59. }
  60. flush(false);
  61. }
  62. void CommonXmlWriter::outputQuoted(const char *text)
  63. {
  64. out.append(text);
  65. }
  66. void CommonXmlWriter::outputString(unsigned len, const char *field, const char *fieldname)
  67. {
  68. if (flags & XWFtrim)
  69. len = rtlTrimStrLen(len, field);
  70. if ((flags & XWFopt) && (rtlTrimStrLen(len, field) == 0))
  71. return;
  72. if (checkForAttribute(fieldname))
  73. outputXmlAttrString(len, field, fieldname+1, out);
  74. else
  75. {
  76. if (!nestLimit)
  77. out.pad(indent);
  78. outputXmlString(len, field, fieldname, out);
  79. if (!nestLimit)
  80. out.newline();
  81. }
  82. }
  83. void CommonXmlWriter::outputQString(unsigned len, const char *field, const char *fieldname)
  84. {
  85. MemoryAttr tempBuffer;
  86. char * temp;
  87. if (len <= 100)
  88. temp = (char *)alloca(len);
  89. else
  90. temp = (char *)tempBuffer.allocate(len);
  91. rtlQStrToStr(len, temp, len, field);
  92. // outputString(len, temp, fieldname, isnumeric);
  93. outputString(len, temp, fieldname);
  94. }
  95. void CommonXmlWriter::outputBool(bool field, const char *fieldname)
  96. {
  97. if (checkForAttribute(fieldname))
  98. outputXmlAttrBool(field, fieldname+1, out);
  99. else
  100. {
  101. if (!nestLimit)
  102. out.pad(indent);
  103. outputXmlBool(field, fieldname, out);
  104. if (!nestLimit)
  105. out.newline();
  106. }
  107. }
  108. void CommonXmlWriter::outputData(unsigned len, const void *field, const char *fieldname)
  109. {
  110. if (checkForAttribute(fieldname))
  111. outputXmlAttrData(len, field, fieldname+1, out);
  112. else
  113. {
  114. if (!nestLimit)
  115. out.pad(indent);
  116. outputXmlData(len, field, fieldname, out);
  117. if (!nestLimit)
  118. out.newline();
  119. }
  120. }
  121. void CommonXmlWriter::outputInt(__int64 field, unsigned size, const char *fieldname)
  122. {
  123. if (checkForAttribute(fieldname))
  124. outputXmlAttrInt(field, fieldname+1, out);
  125. else
  126. {
  127. if (!nestLimit)
  128. out.pad(indent);
  129. outputXmlInt(field, fieldname, out);
  130. if (!nestLimit)
  131. out.newline();
  132. }
  133. }
  134. void CommonXmlWriter::outputUInt(unsigned __int64 field, unsigned size, const char *fieldname)
  135. {
  136. if (checkForAttribute(fieldname))
  137. outputXmlAttrUInt(field, fieldname+1, out);
  138. else
  139. {
  140. if (!nestLimit)
  141. out.pad(indent);
  142. outputXmlUInt(field, fieldname, out);
  143. if (!nestLimit)
  144. out.newline();
  145. }
  146. }
  147. void CommonXmlWriter::outputReal(double field, const char *fieldname)
  148. {
  149. if (checkForAttribute(fieldname))
  150. outputXmlAttrReal(field, fieldname+1, out);
  151. else
  152. {
  153. if (!nestLimit)
  154. out.pad(indent);
  155. outputXmlReal(field, fieldname, out);
  156. if (!nestLimit)
  157. out.newline();
  158. }
  159. }
  160. void CommonXmlWriter::outputDecimal(const void *field, unsigned size, unsigned precision, const char *fieldname)
  161. {
  162. if (checkForAttribute(fieldname))
  163. outputXmlAttrDecimal(field, size, precision, fieldname+1, out);
  164. else
  165. {
  166. if (!nestLimit)
  167. out.pad(indent);
  168. outputXmlDecimal(field, size, precision, fieldname, out);
  169. if (!nestLimit)
  170. out.newline();
  171. }
  172. }
  173. void CommonXmlWriter::outputUDecimal(const void *field, unsigned size, unsigned precision, const char *fieldname)
  174. {
  175. if (checkForAttribute(fieldname))
  176. outputXmlAttrUDecimal(field, size, precision, fieldname+1, out);
  177. else
  178. {
  179. if (!nestLimit)
  180. out.pad(indent);
  181. outputXmlUDecimal(field, size, precision, fieldname, out);
  182. if (!nestLimit)
  183. out.newline();
  184. }
  185. }
  186. void CommonXmlWriter::outputUnicode(unsigned len, const UChar *field, const char *fieldname)
  187. {
  188. if (flags & XWFtrim)
  189. len = rtlTrimUnicodeStrLen(len, field);
  190. if ((flags & XWFopt) && (rtlTrimUnicodeStrLen(len, field) == 0))
  191. return;
  192. if (checkForAttribute(fieldname))
  193. outputXmlAttrUnicode(len, field, fieldname+1, out);
  194. else
  195. {
  196. if (!nestLimit)
  197. out.pad(indent);
  198. outputXmlUnicode(len, field, fieldname, out);
  199. if (!nestLimit)
  200. out.newline();
  201. }
  202. }
  203. void CommonXmlWriter::outputUtf8(unsigned len, const char *field, const char *fieldname)
  204. {
  205. if (flags & XWFtrim)
  206. len = rtlTrimUtf8StrLen(len, field);
  207. if ((flags & XWFopt) && (rtlTrimUtf8StrLen(len, field) == 0))
  208. return;
  209. if (checkForAttribute(fieldname))
  210. outputXmlAttrUtf8(len, field, fieldname+1, out);
  211. else
  212. {
  213. if (!nestLimit)
  214. out.pad(indent);
  215. outputXmlUtf8(len, field, fieldname, out);
  216. if (!nestLimit)
  217. out.newline();
  218. }
  219. }
  220. void CommonXmlWriter::outputXmlns(const char *name, const char *uri)
  221. {
  222. StringBuffer fieldname;
  223. if (!streq(name, "xmlns"))
  224. fieldname.append("xmlns:");
  225. outputXmlAttrUtf8(rtlUtf8Length(strlen(uri), uri), uri, fieldname.append(name), out);
  226. }
  227. void CommonXmlWriter::outputBeginDataset(const char *dsname, bool nestChildren)
  228. {
  229. outputBeginNested("Dataset", nestChildren, false); //indent row, not dataset for backward compatibility
  230. if (nestChildren && indent==0)
  231. indent++;
  232. if (!dsname || !*dsname)
  233. return;
  234. out.append(" name='"); //single quote for backward compatibility
  235. outputXmlUtf8(rtlUtf8Length(strlen(dsname), dsname), dsname, NULL, out);
  236. out.append("'");
  237. }
  238. void CommonXmlWriter::outputEndDataset(const char *dsname)
  239. {
  240. outputEndNested("Dataset", false);
  241. }
  242. void CommonXmlWriter::outputBeginNested(const char *fieldname, bool nestChildren, bool doIndent)
  243. {
  244. if (!fieldname || !*fieldname)
  245. return;
  246. const char * sep = strchr(fieldname, '/');
  247. if (sep)
  248. {
  249. StringAttr leading(fieldname, sep-fieldname);
  250. outputBeginNested(leading, nestChildren, doIndent);
  251. outputBeginNested(sep+1, nestChildren, doIndent);
  252. return;
  253. }
  254. closeTag();
  255. if (!nestLimit && doIndent)
  256. out.pad(indent);
  257. out.append('<').append(fieldname);
  258. if (doIndent)
  259. indent += 1;
  260. if (!nestChildren && !nestLimit)
  261. nestLimit = indent;
  262. tagClosed = false;
  263. }
  264. void CommonXmlWriter::outputBeginNested(const char *fieldname, bool nestChildren)
  265. {
  266. outputBeginNested(fieldname, nestChildren, true);
  267. }
  268. void CommonXmlWriter::outputEndNested(const char *fieldname, bool doIndent)
  269. {
  270. if (!fieldname || !*fieldname)
  271. return;
  272. const char * sep = strchr(fieldname, '/');
  273. if (sep)
  274. {
  275. StringAttr leading(fieldname, sep-fieldname);
  276. outputEndNested(sep+1, doIndent);
  277. outputEndNested(leading, doIndent);
  278. return;
  279. }
  280. if (flags & XWFexpandempty)
  281. closeTag();
  282. if (!tagClosed)
  283. {
  284. out.append("/>");
  285. tagClosed = true;
  286. }
  287. else
  288. {
  289. if (!nestLimit && doIndent)
  290. out.pad(indent-1);
  291. out.append("</").append(fieldname).append('>');
  292. }
  293. if (indent==nestLimit)
  294. nestLimit = 0;
  295. if (doIndent)
  296. indent -= 1;
  297. if (!nestLimit)
  298. out.newline();
  299. }
  300. void CommonXmlWriter::outputEndNested(const char *fieldname)
  301. {
  302. outputEndNested(fieldname, true);
  303. }
  304. void CommonXmlWriter::outputSetAll()
  305. {
  306. closeTag();
  307. if (!nestLimit)
  308. out.pad(indent);
  309. outputXmlSetAll(out);
  310. if (!nestLimit)
  311. out.newline();
  312. }
  313. //=====================================================================================
  314. CommonJsonWriter::CommonJsonWriter(unsigned _flags, unsigned initialIndent, IXmlStreamFlusher *_flusher)
  315. {
  316. flusher = _flusher;
  317. flags = _flags;
  318. indent = initialIndent;
  319. nestLimit = flags & XWFnoindent ? (unsigned) -1 : 0;
  320. needDelimiter = false;
  321. }
  322. CommonJsonWriter::~CommonJsonWriter()
  323. {
  324. flush(true);
  325. }
  326. IXmlWriterExt & CommonJsonWriter::clear()
  327. {
  328. out.clear();
  329. indent = 0;
  330. nestLimit = flags & XWFnoindent ? (unsigned) -1 : 0;
  331. return *this;
  332. }
  333. void CommonJsonWriter::checkFormat(bool doDelimit, bool delimitNext, int inc)
  334. {
  335. if (doDelimit)
  336. {
  337. if (needDelimiter)
  338. {
  339. if (!out.length()) //new block
  340. out.append(',');
  341. else
  342. delimitJSON(out);
  343. }
  344. if (!nestLimit)
  345. out.append('\n').pad(indent);
  346. }
  347. indent+=inc;
  348. needDelimiter = delimitNext;
  349. }
  350. void CommonJsonWriter::checkDelimit(int inc)
  351. {
  352. checkFormat(true, true, inc);
  353. }
  354. const char *CommonJsonWriter::checkItemName(CJsonWriterItem *item, const char *name, bool simpleType)
  355. {
  356. if (simpleType && (!name || !*name))
  357. name = "#value"; //xml mixed content
  358. if (item && item->depth==0 && strieq(item->name, name))
  359. return NULL;
  360. return name;
  361. }
  362. const char *CommonJsonWriter::checkItemName(const char *name, bool simpleType)
  363. {
  364. CJsonWriterItem *item = (arrays.length()) ? &arrays.tos() : NULL;
  365. return checkItemName(item, name, simpleType);
  366. }
  367. const char *CommonJsonWriter::checkItemNameBeginNested(const char *name)
  368. {
  369. CJsonWriterItem *item = (arrays.length()) ? &arrays.tos() : NULL;
  370. name = checkItemName(item, name, false);
  371. if (item)
  372. item->depth++;
  373. return name;
  374. }
  375. bool CommonJsonWriter::checkUnamedArrayItem(bool begin)
  376. {
  377. CJsonWriterItem *item = (arrays.length()) ? &arrays.tos() : NULL;
  378. if (item && item->depth==(begin ? 0 : 1) && item->name.isEmpty())
  379. return true;
  380. return false;
  381. }
  382. const char *CommonJsonWriter::checkItemNameEndNested(const char *name)
  383. {
  384. CJsonWriterItem *item = (arrays.length()) ? &arrays.tos() : NULL;
  385. if (item)
  386. item->depth--;
  387. return checkItemName(item, name, false);
  388. }
  389. void CommonJsonWriter::outputQuoted(const char *text)
  390. {
  391. checkDelimit();
  392. appendJSONValue(out, NULL, text);
  393. }
  394. void CommonJsonWriter::outputNumericString(const char *field, const char *fieldname)
  395. {
  396. unsigned len = (size32_t)strlen(field);
  397. if (flags & XWFtrim)
  398. len = rtlTrimStrLen(len, field);
  399. if ((flags & XWFopt) && (rtlTrimStrLen(len, field) == 0))
  400. return;
  401. checkDelimit();
  402. appendJSONStringValue(out, checkItemName(fieldname), len, field, true, false);
  403. }
  404. void CommonJsonWriter::outputString(unsigned len, const char *field, const char *fieldname)
  405. {
  406. if (flags & XWFtrim)
  407. len = rtlTrimStrLen(len, field);
  408. if ((flags & XWFopt) && (rtlTrimStrLen(len, field) == 0))
  409. return;
  410. checkDelimit();
  411. appendJSONStringValue(out, checkItemName(fieldname), len, field, true);
  412. }
  413. void CommonJsonWriter::outputQString(unsigned len, const char *field, const char *fieldname)
  414. {
  415. MemoryAttr tempBuffer;
  416. char * temp;
  417. if (len <= 100)
  418. temp = (char *)alloca(len);
  419. else
  420. temp = (char *)tempBuffer.allocate(len);
  421. rtlQStrToStr(len, temp, len, field);
  422. outputString(len, temp, fieldname);
  423. }
  424. void CommonJsonWriter::outputBool(bool field, const char *fieldname)
  425. {
  426. checkDelimit();
  427. appendJSONValue(out, checkItemName(fieldname), field);
  428. }
  429. void CommonJsonWriter::outputData(unsigned len, const void *field, const char *fieldname)
  430. {
  431. checkDelimit();
  432. appendJSONDataValue(out, checkItemName(fieldname), len, field);
  433. }
  434. void CommonJsonWriter::outputInt(__int64 field, unsigned size, const char *fieldname)
  435. {
  436. if (size < 7) //JavaScript only supports 53 significant bits
  437. {
  438. checkDelimit();
  439. appendJSONValue(out, checkItemName(fieldname), field);
  440. }
  441. else
  442. {
  443. appendJSONNameOrDelimit(out, checkItemName(fieldname));
  444. out.append('"').append(field).append('"');
  445. }
  446. }
  447. void CommonJsonWriter::outputUInt(unsigned __int64 field, unsigned size, const char *fieldname)
  448. {
  449. if (size < 7) //JavaScript doesn't support unsigned, and only supports 53 significant bits
  450. {
  451. checkDelimit();
  452. appendJSONValue(out, checkItemName(fieldname), field);
  453. }
  454. else
  455. {
  456. appendJSONNameOrDelimit(out, checkItemName(fieldname));
  457. out.append('"').append(field).append('"');
  458. }
  459. }
  460. void CommonJsonWriter::outputReal(double field, const char *fieldname)
  461. {
  462. checkDelimit();
  463. appendJSONValue(out, checkItemName(fieldname), field);
  464. }
  465. void CommonJsonWriter::outputDecimal(const void *field, unsigned size, unsigned precision, const char *fieldname)
  466. {
  467. checkDelimit();
  468. outputJsonDecimal(field, size, precision, checkItemName(fieldname), out);
  469. }
  470. void CommonJsonWriter::outputUDecimal(const void *field, unsigned size, unsigned precision, const char *fieldname)
  471. {
  472. checkDelimit();
  473. outputJsonUDecimal(field, size, precision, checkItemName(fieldname), out);
  474. }
  475. void CommonJsonWriter::outputUnicode(unsigned len, const UChar *field, const char *fieldname)
  476. {
  477. if (flags & XWFtrim)
  478. len = rtlTrimUnicodeStrLen(len, field);
  479. if ((flags & XWFopt) && (rtlTrimUnicodeStrLen(len, field) == 0))
  480. return;
  481. checkDelimit();
  482. outputJsonUnicode(len, field, checkItemName(fieldname), out);
  483. }
  484. void CommonJsonWriter::outputUtf8(unsigned len, const char *field, const char *fieldname)
  485. {
  486. if (flags & XWFtrim)
  487. len = rtlTrimUtf8StrLen(len, field);
  488. if ((flags & XWFopt) && (rtlTrimUtf8StrLen(len, field) == 0))
  489. return;
  490. checkDelimit();
  491. appendJSONStringValue(out, checkItemName(fieldname), rtlUtf8Size(len, field), field, true);
  492. }
  493. void CommonJsonWriter::prepareBeginArray(const char *fieldname)
  494. {
  495. arrays.append(*new CJsonWriterItem(fieldname));
  496. const char * sep = (fieldname) ? strchr(fieldname, '/') : NULL;
  497. while (sep)
  498. {
  499. StringAttr leading(fieldname, sep-fieldname);
  500. appendJSONName(out, leading).append(" {");
  501. fieldname = sep+1;
  502. sep = strchr(fieldname, '/');
  503. }
  504. checkFormat(false, false, 1);
  505. }
  506. void CommonJsonWriter::outputBeginArray(const char *fieldname)
  507. {
  508. prepareBeginArray(fieldname);
  509. appendJSONName(out, fieldname).append('[');
  510. }
  511. void CommonJsonWriter::outputEndArray(const char *fieldname)
  512. {
  513. arrays.pop();
  514. checkFormat(false, true, -1);
  515. out.append(']');
  516. const char * sep = (fieldname) ? strchr(fieldname, '/') : NULL;
  517. while (sep)
  518. {
  519. out.append('}');
  520. sep = strchr(sep+1, '/');
  521. }
  522. }
  523. void CommonJsonWriter::outputBeginDataset(const char *dsname, bool nestChildren)
  524. {
  525. if (dsname && *dsname)
  526. outputBeginNested(dsname, nestChildren);
  527. }
  528. void CommonJsonWriter::outputEndDataset(const char *dsname)
  529. {
  530. if (dsname && *dsname)
  531. outputEndNested(dsname);
  532. }
  533. void CommonJsonWriter::outputBeginNested(const char *fieldname, bool nestChildren)
  534. {
  535. if (!fieldname)
  536. return;
  537. if (!*fieldname && !checkUnamedArrayItem(true))
  538. return;
  539. flush(false);
  540. checkFormat(true, false, 1);
  541. fieldname = checkItemNameBeginNested(fieldname);
  542. if (fieldname && *fieldname)
  543. {
  544. const char * sep = (fieldname) ? strchr(fieldname, '/') : NULL;
  545. while (sep)
  546. {
  547. StringAttr leading(fieldname, sep-fieldname);
  548. appendJSONName(out, leading).append("{");
  549. fieldname = sep+1;
  550. sep = strchr(fieldname, '/');
  551. }
  552. appendJSONName(out, fieldname);
  553. }
  554. out.append("{");
  555. if (!nestChildren && !nestLimit)
  556. nestLimit = indent;
  557. }
  558. void CommonJsonWriter::outputEndNested(const char *fieldname)
  559. {
  560. if (!fieldname)
  561. return;
  562. if (!*fieldname && !checkUnamedArrayItem(false))
  563. return;
  564. flush(false);
  565. checkFormat(false, true, -1);
  566. fieldname = checkItemNameEndNested(fieldname);
  567. if (fieldname && *fieldname)
  568. {
  569. const char * sep = (fieldname) ? strchr(fieldname, '/') : NULL;
  570. while (sep)
  571. {
  572. out.append('}');
  573. sep = strchr(sep+1, '/');
  574. }
  575. }
  576. out.append("}");
  577. if (indent==nestLimit)
  578. nestLimit = 0;
  579. }
  580. void CommonJsonWriter::outputSetAll()
  581. {
  582. flush(false);
  583. checkDelimit();
  584. appendJSONValue(out, "All", true);
  585. }
  586. StringBuffer &buildJsonHeader(StringBuffer &header, const char *suppliedHeader, const char *rowTag)
  587. {
  588. if (suppliedHeader)
  589. {
  590. header.append(suppliedHeader);
  591. if (rowTag && *rowTag)
  592. appendJSONName(header, rowTag).append('[');
  593. return header;
  594. }
  595. if (rowTag && *rowTag)
  596. {
  597. header.append('{');
  598. appendJSONName(header, rowTag);
  599. }
  600. return header.append('[');
  601. }
  602. StringBuffer &buildJsonFooter(StringBuffer &footer, const char *suppliedFooter, const char *rowTag)
  603. {
  604. if (suppliedFooter)
  605. {
  606. if (rowTag && *rowTag)
  607. footer.append(']');
  608. footer.append(suppliedFooter);
  609. return footer;
  610. }
  611. return footer.append((rowTag && *rowTag) ? "]}" : "]");
  612. }
  613. static char thorHelperhexchar[] = "0123456789ABCDEF";
  614. //=====================================================================================
  615. static char csvQuote = '\"';
  616. CommonCSVWriter::CommonCSVWriter(unsigned _flags, CSVOptions& _options, IXmlStreamFlusher* _flusher)
  617. {
  618. flusher = _flusher;
  619. flags = _flags;
  620. options.terminator.set(_options.terminator.get());
  621. options.delimiter.set(_options.delimiter.get());
  622. options.includeHeader = _options.includeHeader; //output CSV headers
  623. recordCount = headerColumnID = 0;
  624. nestedHeaderLayerID = 0;
  625. readingCSVHeader = true;
  626. addingSimpleNestedContent = false; //Set by CommonCSVWriter::checkHeaderName()
  627. }
  628. CommonCSVWriter::~CommonCSVWriter()
  629. {
  630. flush(true);
  631. }
  632. void CommonCSVWriter::outputString(unsigned len, const char* field, const char* fieldName)
  633. {
  634. if (!checkHeaderName(fieldName))
  635. return;
  636. addStringField(len, field, fieldName);
  637. }
  638. void CommonCSVWriter::outputBool(bool field, const char* fieldName)
  639. {
  640. if (!checkHeaderName(fieldName))
  641. return;
  642. addContentField((field) ? "true" : "false", fieldName);
  643. }
  644. void CommonCSVWriter::outputData(unsigned len, const void* field, const char* fieldName)
  645. {
  646. if (!checkHeaderName(fieldName))
  647. return;
  648. StringBuffer v;
  649. const unsigned char *value = (const unsigned char *) field;
  650. for (unsigned int i = 0; i < len; i++)
  651. v.append(thorHelperhexchar[value[i] >> 4]).append(thorHelperhexchar[value[i] & 0x0f]);
  652. addContentField(v.str(), fieldName);
  653. }
  654. void CommonCSVWriter::outputInt(__int64 field, unsigned size, const char* fieldName)
  655. {
  656. if (!checkHeaderName(fieldName))
  657. return;
  658. StringBuffer v;
  659. v.append(field);
  660. addContentField(v.str(), fieldName);
  661. }
  662. void CommonCSVWriter::outputUInt(unsigned __int64 field, unsigned size, const char* fieldName)
  663. {
  664. if (!checkHeaderName(fieldName))
  665. return;
  666. StringBuffer v;
  667. v.append(field);
  668. addContentField(v.str(), fieldName);
  669. }
  670. void CommonCSVWriter::outputReal(double field, const char *fieldName)
  671. {
  672. if (!checkHeaderName(fieldName))
  673. return;
  674. StringBuffer v;
  675. v.append(field);
  676. addContentField(v.str(), fieldName);
  677. }
  678. void CommonCSVWriter::outputDecimal(const void* field, unsigned size, unsigned precision, const char* fieldName)
  679. {
  680. if (!checkHeaderName(fieldName))
  681. return;
  682. StringBuffer v;
  683. char dec[50];
  684. BcdCriticalBlock bcdBlock;
  685. if (DecValid(true, size*2-1, field))
  686. {
  687. DecPushDecimal(field, size, precision);
  688. DecPopCString(sizeof(dec), dec);
  689. const char *finger = dec;
  690. while(isspace(*finger)) finger++;
  691. v.append(finger);
  692. }
  693. addContentField(v.str(), fieldName);
  694. }
  695. void CommonCSVWriter::outputUDecimal(const void* field, unsigned size, unsigned precision, const char* fieldName)
  696. {
  697. if (!checkHeaderName(fieldName))
  698. return;
  699. StringBuffer v;
  700. char dec[50];
  701. BcdCriticalBlock bcdBlock;
  702. if (DecValid(false, size*2, field))
  703. {
  704. DecPushUDecimal(field, size, precision);
  705. DecPopCString(sizeof(dec), dec);
  706. const char *finger = dec;
  707. while(isspace(*finger)) finger++;
  708. v.append(finger);
  709. }
  710. addContentField(v.str(), fieldName);
  711. }
  712. void CommonCSVWriter::outputUnicode(unsigned len, const UChar* field, const char* fieldName)
  713. {
  714. if (!checkHeaderName(fieldName))
  715. return;
  716. StringBuffer v;
  717. char * buff = 0;
  718. unsigned bufflen = 0;
  719. rtlUnicodeToCodepageX(bufflen, buff, len, field, "utf-8");
  720. addStringField(bufflen, buff, fieldName);
  721. rtlFree(buff);
  722. }
  723. void CommonCSVWriter::outputQString(unsigned len, const char* field, const char* fieldName)
  724. {
  725. if (!checkHeaderName(fieldName))
  726. return;
  727. MemoryAttr tempBuffer;
  728. char * temp;
  729. if (len <= 100)
  730. temp = (char *)alloca(len);
  731. else
  732. temp = (char *)tempBuffer.allocate(len);
  733. rtlQStrToStr(len, temp, len, field);
  734. addStringField(len, temp, fieldName);
  735. }
  736. void CommonCSVWriter::outputUtf8(unsigned len, const char* field, const char* fieldName)
  737. {
  738. if (!checkHeaderName(fieldName))
  739. return;
  740. addStringField(rtlUtf8Size(len, field), field, fieldName);
  741. }
  742. void CommonCSVWriter::outputNumericString(const char* field, const char* fieldName)
  743. {
  744. if (!checkHeaderName(fieldName))
  745. return;
  746. addStringField((size32_t)strlen(field), field, fieldName);
  747. }
  748. void CommonCSVWriter::appendDataXPathItem(const char* fieldName, bool isArray)
  749. {
  750. Owned<CXPathItem> item = new CXPathItem(fieldName, isArray);
  751. dataXPath.append(*item.getClear());
  752. }
  753. bool CommonCSVWriter::isDataRow(const char* fieldName)
  754. {
  755. if (dataXPath.empty())
  756. return false;
  757. CXPathItem& xPathItem = dataXPath.item(dataXPath.length() - 1);
  758. return xPathItem.getIsArray() && strieq(fieldName, xPathItem.getPath());
  759. }
  760. void CommonCSVWriter::outputBeginNested(const char* fieldName, bool simpleNested, bool outputHeader)
  761. {
  762. //This method is called when retrieving csv headers.
  763. if (!fieldName || !*fieldName || !readingCSVHeader)
  764. return;
  765. addCSVHeader(fieldName, NULL, true, simpleNested, outputHeader);
  766. if (simpleNested) //ECL SET has only one column (parent name should be used as column name).
  767. headerColumnID++;
  768. //nestedHeaderLayerID is used as row ID when output CSV headers.
  769. if (outputHeader)
  770. nestedHeaderLayerID++;
  771. addFieldToParentXPath(fieldName);
  772. }
  773. void CommonCSVWriter::outputEndNested(const char* fieldName, bool outputHeader)
  774. {
  775. //This method is called when retrieving csv headers.
  776. if (!fieldName || !*fieldName || !readingCSVHeader)
  777. return;
  778. removeFieldFromCurrentParentXPath(fieldName);
  779. if (outputHeader)
  780. nestedHeaderLayerID--;
  781. }
  782. void CommonCSVWriter::outputBeginNested(const char* fieldName, bool simpleNested)
  783. {
  784. if (!fieldName || !*fieldName || readingCSVHeader)
  785. return;
  786. if (!isDataRow(fieldName))
  787. {//A nested item begins.
  788. //Call appendDataXPathItem() after the isDataRpw()
  789. //because previous data xpath is used in isDataRpw().
  790. appendDataXPathItem(fieldName, false);
  791. addFieldToParentXPath(fieldName);
  792. }
  793. else
  794. {//A new row begins inside a nested item.
  795. appendDataXPathItem(fieldName, false);
  796. if (!currentParentXPath.isEmpty())
  797. {
  798. //Add row xpath if it is not the 1st xpath.
  799. addFieldToParentXPath(fieldName);
  800. CCSVItem* item = getParentCSVItem();
  801. if (!item)
  802. return;
  803. //Check row count for the ParentCSVItem.
  804. //If this is not the first row, all children of the ParentCSVItem should
  805. //start from the MaxNextRowID of the last row.
  806. unsigned rowCount = item->getRowCount();
  807. if (rowCount > 0)
  808. {//Starting from the second result row, the NextRowIDs of every children are reset based on the last result row.
  809. StringBuffer path = currentParentXPath;
  810. path.setLength(path.length() - 1);
  811. setChildrenNextRowID(path.str(), getChildrenMaxNextRowID(path.str()));
  812. }
  813. item->setCurrentRowEmpty(true);
  814. }
  815. }
  816. }
  817. void CommonCSVWriter::outputEndNested(const char* fieldName)
  818. {
  819. if (!fieldName || !*fieldName || readingCSVHeader)
  820. return;
  821. dataXPath.pop();
  822. if (!isDataRow(fieldName))
  823. {//This is an end of a nested item.
  824. removeFieldFromCurrentParentXPath(fieldName);
  825. }
  826. else
  827. {//A row ends inside the nested item
  828. //Set row count for ParentCSVItem of this field.
  829. if (!currentParentXPath.isEmpty())
  830. {
  831. CCSVItem* item = getParentCSVItem();
  832. if (item && !item->getCurrentRowEmpty())
  833. {
  834. //Increase row count for this item
  835. item->incrementRowCount();
  836. item->setCurrentRowEmpty(true);
  837. }
  838. }
  839. removeFieldFromCurrentParentXPath(fieldName);
  840. //if dataXPath.length() back to 1, this should be the end of a content result row.
  841. if (dataXPath.length() == 1)
  842. finishContentResultRow();
  843. }
  844. }
  845. void CommonCSVWriter::outputBeginArray(const char* fieldName)
  846. {
  847. appendDataXPathItem(fieldName, true);
  848. };
  849. void CommonCSVWriter::outputEndArray(const char* fieldName)
  850. {
  851. dataXPath.pop();
  852. };
  853. void CommonCSVWriter::outputBeginDataset(const char* dsname, bool nestChildren)
  854. {
  855. //This is called to add a <Dataset> tag outside of a wu result xml. No need for csv.
  856. };
  857. void CommonCSVWriter::outputEndDataset(const char* dsname)
  858. {
  859. };
  860. IXmlWriterExt& CommonCSVWriter::clear()
  861. {
  862. recordCount = /*rowCount =*/ headerColumnID = 0;
  863. nestedHeaderLayerID = 0;
  864. readingCSVHeader = true;
  865. addingSimpleNestedContent = false;
  866. currentParentXPath.clear();
  867. headerXPathList.kill();
  868. topHeaderNameMap.kill();
  869. contentRowsBuffer.clear();
  870. csvItems.kill();
  871. out.clear();
  872. auditOut.clear();
  873. return *this;
  874. };
  875. void CommonCSVWriter::outputCSVHeader(const char* name, const char* type)
  876. {
  877. if (!name || !*name)
  878. return;
  879. addCSVHeader(name, type, false, false, true);
  880. headerColumnID++;
  881. }
  882. void CommonCSVWriter::finishCSVHeaders()
  883. {
  884. if (options.includeHeader)
  885. outputHeadersToBuffer();
  886. readingCSVHeader = false;
  887. currentParentXPath.clear();
  888. #ifdef _DEBUG
  889. auditHeaderInfo();
  890. #endif
  891. }
  892. void CommonCSVWriter::outputHeadersToBuffer()
  893. {
  894. CIArrayOf<CCSVRow> rows;
  895. ForEachItemIn(i, headerXPathList)
  896. {
  897. const char* path = headerXPathList.item(i);
  898. CCSVItem* item = csvItems.getValue(path);
  899. if (!item || !item->checkOutputHeader())
  900. continue;
  901. unsigned colID = item->getColumnID();
  902. if (item->checkIsNestedItem())
  903. {
  904. unsigned maxColumnID = colID;
  905. getChildrenMaxColumnID(item, maxColumnID);
  906. colID += (maxColumnID - colID)/2;
  907. }
  908. addColumnToRow(rows, item->getNestedLayer(), colID, item->getName(), NULL);
  909. }
  910. outputCSVRows(rows, true);
  911. }
  912. //Go through every children to find out MaxColumnID.
  913. unsigned CommonCSVWriter::getChildrenMaxColumnID(CCSVItem* item, unsigned& maxColumnID)
  914. {
  915. StringBuffer path = item->getParentXPath();
  916. path.append(item->getName());
  917. StringArray& names = item->getChildrenNames();
  918. ForEachItemIn(i, names)
  919. {
  920. StringBuffer childPath = path;
  921. childPath.append("/").append(names.item(i));
  922. CCSVItem* childItem = csvItems.getValue(childPath.str());
  923. if (!childItem)
  924. continue;
  925. if (childItem->checkIsNestedItem())
  926. maxColumnID = getChildrenMaxColumnID(childItem, maxColumnID);
  927. else
  928. {
  929. unsigned columnID = childItem->getColumnID();
  930. if (columnID > maxColumnID)
  931. maxColumnID = columnID;
  932. }
  933. }
  934. return maxColumnID;
  935. }
  936. void CommonCSVWriter::escapeQuoted(unsigned len, char const* in, StringBuffer& out)
  937. {
  938. char const* finger = in;
  939. while (len--)
  940. {
  941. //RFC-4180, paragraph "If double-quotes are used to enclose fields, then a double-quote
  942. //appearing inside a field must be escaped by preceding it with another double quote."
  943. //unsigned newLen = 0;
  944. if (*finger == '"')
  945. out.append('"');
  946. out.append(*finger);
  947. finger++;
  948. }
  949. }
  950. CCSVItem* CommonCSVWriter::getParentCSVItem()
  951. {
  952. if (currentParentXPath.isEmpty())
  953. return NULL;
  954. StringBuffer path = currentParentXPath;
  955. path.setLength(path.length() - 1);
  956. return csvItems.getValue(path.str());
  957. }
  958. CCSVItem* CommonCSVWriter::getCSVItemByFieldName(const char* name)
  959. {
  960. StringBuffer path;
  961. if (currentParentXPath.isEmpty())
  962. path.append(name);
  963. else
  964. path.append(currentParentXPath.str()).append(name);
  965. return csvItems.getValue(path.str());
  966. }
  967. bool CommonCSVWriter::checkHeaderName(const char* name)
  968. {
  969. if (!name || !*name)
  970. return false;
  971. if (currentParentXPath.isEmpty())
  972. {
  973. bool* found = topHeaderNameMap.getValue(name);
  974. return (found && *found);
  975. }
  976. CCSVItem* item = getParentCSVItem();
  977. if (!item)
  978. return false;
  979. addingSimpleNestedContent = item->checkSimpleNested();
  980. if (addingSimpleNestedContent) //ECL: SET OF string, int, etc
  981. return true;
  982. return item->hasChildName(name);
  983. }
  984. void CommonCSVWriter::addColumnToRow(CIArrayOf<CCSVRow>& rows, unsigned rowID, unsigned colID, const char* columnValue, const char* columnName)
  985. {
  986. if (!columnValue)
  987. columnValue = "";
  988. if (rowID < rows.length())
  989. { //add the column to existing row
  990. CCSVRow& row = rows.item(rowID);
  991. row.setColumn(colID, NULL, columnValue);
  992. }
  993. else
  994. { //new row
  995. Owned<CCSVRow> newRow = new CCSVRow(rowID);
  996. newRow->setColumn(colID, NULL, columnValue);
  997. rows.append(*newRow.getClear());
  998. }
  999. if (currentParentXPath.isEmpty())
  1000. return;
  1001. if (!addingSimpleNestedContent && columnName && *columnName)
  1002. {
  1003. CCSVItem* item = getCSVItemByFieldName(columnName);
  1004. if (item)
  1005. item->incrementNextRowID();
  1006. }
  1007. CCSVItem* parentItem = getParentCSVItem();
  1008. if (parentItem)
  1009. {
  1010. if (addingSimpleNestedContent) //ECL: SET OF string, int, etc. NextRowID should be stored in Parent item.
  1011. parentItem->incrementNextRowID();
  1012. setParentItemRowEmpty(parentItem, false);
  1013. }
  1014. }
  1015. void CommonCSVWriter::setParentItemRowEmpty(CCSVItem* item, bool empty)
  1016. {
  1017. item->setCurrentRowEmpty(empty);
  1018. StringBuffer parentXPath = item->getParentXPath();
  1019. if (parentXPath.isEmpty())
  1020. return;
  1021. //If this item is not empty, its parent is not empty.
  1022. parentXPath.setLength(parentXPath.length() - 1);
  1023. setParentItemRowEmpty(csvItems.getValue(parentXPath), empty);
  1024. }
  1025. void CommonCSVWriter::addCSVHeader(const char* name, const char* type, bool isNested, bool simpleNested, bool outputHeader)
  1026. {
  1027. if (checkHeaderName(name))
  1028. return;//Duplicated header. Should never happen.
  1029. Owned<CCSVItem> headerItem = new CCSVItem();
  1030. headerItem->setName(name);
  1031. headerItem->setIsNestedItem(isNested);
  1032. headerItem->setSimpleNested(simpleNested);
  1033. headerItem->setOutputHeader(outputHeader);
  1034. headerItem->setColumnID(headerColumnID);
  1035. headerItem->setNestedLayer(nestedHeaderLayerID);
  1036. headerItem->setParentXPath(currentParentXPath.str());
  1037. StringBuffer xPath = currentParentXPath;
  1038. xPath.append(name);
  1039. csvItems.setValue(xPath.str(), headerItem);
  1040. headerXPathList.append(xPath.str());
  1041. addChildNameToParentCSVItem(name);
  1042. if (currentParentXPath.isEmpty())
  1043. topHeaderNameMap.setValue(name, true);
  1044. }
  1045. void CommonCSVWriter::addContentField(const char* field, const char* fieldName)
  1046. {
  1047. CCSVItem* item = NULL;
  1048. if (addingSimpleNestedContent) //ECL: SET OF string, int, etc. ColumnID should be stored in Parent item.
  1049. item = getParentCSVItem();
  1050. else
  1051. item = getCSVItemByFieldName(fieldName);
  1052. addColumnToRow(contentRowsBuffer, item ? item->getNextRowID() : 0, item ? item->getColumnID() : 0, field, fieldName);
  1053. }
  1054. void CommonCSVWriter::addStringField(unsigned len, const char* field, const char* fieldName)
  1055. {
  1056. StringBuffer v;
  1057. v.append(csvQuote);
  1058. escapeQuoted(len, field, v);
  1059. v.append(csvQuote);
  1060. addContentField(v.str(), fieldName);
  1061. }
  1062. unsigned CommonCSVWriter::getChildrenMaxNextRowID(const char* path)
  1063. {
  1064. CCSVItem* item = csvItems.getValue(path);
  1065. if (!item)
  1066. return 0; //Should never happen
  1067. if (!item->checkIsNestedItem())
  1068. return item->getNextRowID();
  1069. unsigned maxRowID = item->getNextRowID();
  1070. StringBuffer basePath = path;
  1071. basePath.append("/");
  1072. StringArray& names = item->getChildrenNames();
  1073. ForEachItemIn(i, names)
  1074. {
  1075. StringBuffer childPath = basePath;
  1076. childPath.append(names.item(i));
  1077. unsigned rowID = getChildrenMaxNextRowID(childPath.str());
  1078. if (rowID > maxRowID)
  1079. maxRowID = rowID;
  1080. }
  1081. return maxRowID;
  1082. }
  1083. void CommonCSVWriter::setChildrenNextRowID(const char* path, unsigned rowID)
  1084. {
  1085. CCSVItem* item = csvItems.getValue(path);
  1086. if (!item)
  1087. return;
  1088. if (!item->checkIsNestedItem())
  1089. {
  1090. item->setNextRowID(rowID);
  1091. return;
  1092. }
  1093. StringArray& names = item->getChildrenNames();
  1094. ForEachItemIn(i, names)
  1095. {
  1096. StringBuffer childPath = path;
  1097. childPath.append("/").append(names.item(i));
  1098. CCSVItem* childItem = csvItems.getValue(childPath.str());
  1099. if (!childItem)
  1100. continue;
  1101. childItem->setNextRowID(rowID);//for possible new row
  1102. if (childItem->checkIsNestedItem())
  1103. {
  1104. childItem->setRowCount(0);
  1105. setChildrenNextRowID(childPath.str(), rowID);
  1106. }
  1107. }
  1108. }
  1109. void CommonCSVWriter::addChildNameToParentCSVItem(const char* name)
  1110. {
  1111. if (!name || !*name)
  1112. return;
  1113. if (currentParentXPath.isEmpty())
  1114. return;
  1115. CCSVItem* item = getParentCSVItem();
  1116. if (item)
  1117. item->addChildName(name);
  1118. }
  1119. void CommonCSVWriter::addFieldToParentXPath(const char* fieldName)
  1120. {
  1121. currentParentXPath.append(fieldName).append("/");
  1122. }
  1123. void CommonCSVWriter::removeFieldFromCurrentParentXPath(const char* fieldName)
  1124. {
  1125. unsigned len = strlen(fieldName);
  1126. if (currentParentXPath.length() > len+1)
  1127. currentParentXPath.setLength(currentParentXPath.length() - len - 1);
  1128. else
  1129. currentParentXPath.setLength(0);
  1130. }
  1131. void CommonCSVWriter::outputCSVRows(CIArrayOf<CCSVRow>& rows, bool isHeader)
  1132. {
  1133. bool firstRow = true;
  1134. ForEachItemIn(i, rows)
  1135. {
  1136. if (firstRow && !isHeader)
  1137. {
  1138. out.append(recordCount);
  1139. firstRow = false;
  1140. }
  1141. CCSVRow& row = rows.item(i);
  1142. unsigned len = row.getColumnCount();
  1143. for (unsigned col = 0; col < len; col++)
  1144. out.append(options.delimiter.get()).append(row.getColumnValue(col));
  1145. out.append(options.terminator.get());
  1146. }
  1147. }
  1148. void CommonCSVWriter::finishContentResultRow()
  1149. {
  1150. recordCount++;
  1151. outputCSVRows(contentRowsBuffer, false);
  1152. //Prepare for possible next record
  1153. currentParentXPath.setLength(0);
  1154. contentRowsBuffer.kill();
  1155. ForEachItemIn(i, headerXPathList)
  1156. {
  1157. const char* path = headerXPathList.item(i);
  1158. CCSVItem* item = csvItems.getValue(path);
  1159. if (item)
  1160. item->clearContentVariables();
  1161. }
  1162. };
  1163. void CCSVRow::setColumn(unsigned columnID, const char* columnName, const char* columnValue)
  1164. {
  1165. unsigned len = columns.length();
  1166. if (columnID < len)
  1167. {
  1168. CCSVItem& column = columns.item(columnID);
  1169. if (columnName && *columnName)
  1170. column.setName(columnName);
  1171. column.setValue(columnValue);
  1172. }
  1173. else
  1174. {
  1175. for (unsigned i = len; i <= columnID; i++)
  1176. {
  1177. Owned<CCSVItem> column = new CCSVItem();
  1178. if (i == columnID)
  1179. {
  1180. if (columnName && *columnName)
  1181. column->setName(columnName);
  1182. column->setValue(columnValue);
  1183. }
  1184. columns.append(*column.getClear());
  1185. }
  1186. }
  1187. }
  1188. const char* CCSVRow::getColumnValue(unsigned columnID) const
  1189. {
  1190. if (columnID >= columns.length())
  1191. return ""; //This should never happens.
  1192. CCSVItem& column = columns.item(columnID);
  1193. return column.getValue();
  1194. };
  1195. //=====================================================================================
  1196. inline void outputEncodedXmlString(unsigned len, const char *field, const char *fieldname, StringBuffer &out)
  1197. {
  1198. if (fieldname)
  1199. out.append('<').append(fieldname).append(" xsi:type=\"xsd:string\">");
  1200. encodeXML(field, out, 0, len);
  1201. if (fieldname)
  1202. out.append("</").append(fieldname).append('>');
  1203. }
  1204. inline void outputEncodedXmlBool(bool field, const char *fieldname, StringBuffer &out)
  1205. {
  1206. const char * text = field ? "true" : "false";
  1207. if (fieldname)
  1208. out.append('<').append(fieldname).append(" xsi:type=\"xsd:boolean\">").append(text).append("</").append(fieldname).append('>');
  1209. else
  1210. out.append(text);
  1211. }
  1212. inline void outputEncodedXmlData(unsigned len, const void *_field, const char *fieldname, StringBuffer &out)
  1213. {
  1214. const unsigned char *field = (const unsigned char *) _field;
  1215. if (fieldname)
  1216. out.append('<').append(fieldname).append(" xsi:type=\"xsd:hexBinary\">");
  1217. for (unsigned int i = 0; i < len; i++)
  1218. {
  1219. out.append(thorHelperhexchar[field[i] >> 4]).append(thorHelperhexchar[field[i] & 0x0f]);
  1220. }
  1221. if (fieldname)
  1222. out.append("</").append(fieldname).append('>');
  1223. }
  1224. inline void outputEncoded64XmlData(unsigned len, const void *_field, const char *fieldname, StringBuffer &out)
  1225. {
  1226. if (fieldname)
  1227. out.append('<').append(fieldname).append(" xsi:type=\"xsd:base64Binary\">");
  1228. JBASE64_Encode(_field, len, out, false);
  1229. if (fieldname)
  1230. out.append("</").append(fieldname).append('>');
  1231. }
  1232. inline void outputEncodedXmlInt(__int64 field, const char *fieldname, StringBuffer &out)
  1233. {
  1234. if (fieldname)
  1235. out.append('<').append(fieldname).append(" xsi:type=\"xsd:integer\">").append(field).append("</").append(fieldname).append('>');
  1236. else
  1237. out.append(field);
  1238. }
  1239. inline void outputEncodedXmlUInt(unsigned __int64 field, const char *fieldname, StringBuffer &out)
  1240. {
  1241. if (fieldname)
  1242. out.append('<').append(fieldname).append(" xsi:type=\"xsd:nonNegativeInteger\">").append(field).append("</").append(fieldname).append('>');
  1243. else
  1244. out.append(field);
  1245. }
  1246. inline void outputEncodedXmlReal(double field, const char *fieldname, StringBuffer &out)
  1247. {
  1248. if (fieldname)
  1249. out.append('<').append(fieldname).append(" xsi:type=\"xsd:double\">").append(field).append("</").append(fieldname).append('>');
  1250. else
  1251. out.append(field);
  1252. }
  1253. inline void outputEncodedXmlDecimal(const void *field, unsigned size, unsigned precision, const char *fieldname, StringBuffer &out)
  1254. {
  1255. char dec[50];
  1256. if (fieldname)
  1257. out.append('<').append(fieldname).append(" xsi:type=\"xsd:decimal\">");
  1258. BcdCriticalBlock bcdBlock;
  1259. if (DecValid(true, size*2-1, field))
  1260. {
  1261. DecPushDecimal(field, size, precision);
  1262. DecPopCString(sizeof(dec), dec);
  1263. const char *finger = dec;
  1264. while(isspace(*finger)) finger++;
  1265. out.append(finger);
  1266. }
  1267. else
  1268. out.append("####");
  1269. if (fieldname)
  1270. out.append("</").append(fieldname).append('>');
  1271. }
  1272. inline void outputEncodedXmlUDecimal(const void *field, unsigned size, unsigned precision, const char *fieldname, StringBuffer &out)
  1273. {
  1274. char dec[50];
  1275. if (fieldname)
  1276. out.append('<').append(fieldname).append(" xsi:type=\"xsd:decimal\">");
  1277. BcdCriticalBlock bcdBlock;
  1278. if (DecValid(false, size*2, field))
  1279. {
  1280. DecPushUDecimal(field, size, precision);
  1281. DecPopCString(sizeof(dec), dec);
  1282. const char *finger = dec;
  1283. while(isspace(*finger)) finger++;
  1284. out.append(finger);
  1285. }
  1286. else
  1287. out.append("####");
  1288. if (fieldname)
  1289. out.append("</").append(fieldname).append('>');
  1290. }
  1291. inline void outputEncodedXmlUnicode(unsigned len, const UChar *field, const char *fieldname, StringBuffer &out)
  1292. {
  1293. char * buff = 0;
  1294. unsigned bufflen = 0;
  1295. rtlUnicodeToCodepageX(bufflen, buff, len, field, "utf-8");
  1296. if (fieldname)
  1297. out.append('<').append(fieldname).append(" xsi:type=\"xsd:string\">");
  1298. encodeXML(buff, out, 0, bufflen, true); // output as UTF-8
  1299. if (fieldname)
  1300. out.append("</").append(fieldname).append('>');
  1301. rtlFree(buff);
  1302. }
  1303. inline void outputEncodedXmlUtf8(unsigned len, const char *field, const char *fieldname, StringBuffer &out)
  1304. {
  1305. if (fieldname)
  1306. out.append('<').append(fieldname).append(" xsi:type=\"xsd:string\">");
  1307. encodeXML(field, out, 0, rtlUtf8Size(len, field), true); // output as UTF-8
  1308. if (fieldname)
  1309. out.append("</").append(fieldname).append('>');
  1310. }
  1311. //=====================================================================================
  1312. CommonEncodedXmlWriter::CommonEncodedXmlWriter(unsigned _flags, unsigned initialIndent, IXmlStreamFlusher *_flusher)
  1313. : CommonXmlWriter(_flags, initialIndent, _flusher)
  1314. {
  1315. }
  1316. void CommonEncodedXmlWriter::outputString(unsigned len, const char *field, const char *fieldname)
  1317. {
  1318. if (flags & XWFtrim)
  1319. len = rtlTrimStrLen(len, field);
  1320. if ((flags & XWFopt) && (rtlTrimStrLen(len, field) == 0))
  1321. return;
  1322. if (checkForAttribute(fieldname))
  1323. outputXmlAttrString(len, field, fieldname+1, out);
  1324. else
  1325. {
  1326. if (!nestLimit)
  1327. out.pad(indent);
  1328. outputEncodedXmlString(len, field, fieldname, out);
  1329. if (!nestLimit)
  1330. out.newline();
  1331. }
  1332. }
  1333. void CommonEncodedXmlWriter::outputBool(bool field, const char *fieldname)
  1334. {
  1335. if (checkForAttribute(fieldname))
  1336. outputXmlAttrBool(field, fieldname+1, out);
  1337. else
  1338. {
  1339. if (!nestLimit)
  1340. out.pad(indent);
  1341. outputEncodedXmlBool(field, fieldname, out);
  1342. if (!nestLimit)
  1343. out.newline();
  1344. }
  1345. }
  1346. void CommonEncodedXmlWriter::outputData(unsigned len, const void *field, const char *fieldname)
  1347. {
  1348. if (checkForAttribute(fieldname))
  1349. outputXmlAttrData(len, field, fieldname+1, out);
  1350. else
  1351. {
  1352. if (!nestLimit)
  1353. out.pad(indent);
  1354. outputEncodedXmlData(len, field, fieldname, out);
  1355. if (!nestLimit)
  1356. out.newline();
  1357. }
  1358. }
  1359. void CommonEncodedXmlWriter::outputInt(__int64 field, unsigned size, const char *fieldname)
  1360. {
  1361. if (checkForAttribute(fieldname))
  1362. outputXmlAttrInt(field, fieldname+1, out);
  1363. else
  1364. {
  1365. if (!nestLimit)
  1366. out.pad(indent);
  1367. outputEncodedXmlInt(field, fieldname, out);
  1368. if (!nestLimit)
  1369. out.newline();
  1370. }
  1371. }
  1372. void CommonEncodedXmlWriter::outputUInt(unsigned __int64 field, unsigned size, const char *fieldname)
  1373. {
  1374. if (checkForAttribute(fieldname))
  1375. outputXmlAttrUInt(field, fieldname+1, out);
  1376. else
  1377. {
  1378. if (!nestLimit)
  1379. out.pad(indent);
  1380. outputEncodedXmlUInt(field, fieldname, out);
  1381. if (!nestLimit)
  1382. out.newline();
  1383. }
  1384. }
  1385. void CommonEncodedXmlWriter::outputReal(double field, const char *fieldname)
  1386. {
  1387. if (checkForAttribute(fieldname))
  1388. outputXmlAttrReal(field, fieldname+1, out);
  1389. else
  1390. {
  1391. if (!nestLimit)
  1392. out.pad(indent);
  1393. outputEncodedXmlReal(field, fieldname, out);
  1394. if (!nestLimit)
  1395. out.newline();
  1396. }
  1397. }
  1398. void CommonEncodedXmlWriter::outputDecimal(const void *field, unsigned size, unsigned precision, const char *fieldname)
  1399. {
  1400. if (checkForAttribute(fieldname))
  1401. outputXmlAttrDecimal(field, size, precision, fieldname+1, out);
  1402. else
  1403. {
  1404. if (!nestLimit)
  1405. out.pad(indent);
  1406. outputEncodedXmlDecimal(field, size, precision, fieldname, out);
  1407. if (!nestLimit)
  1408. out.newline();
  1409. }
  1410. }
  1411. void CommonEncodedXmlWriter::outputUDecimal(const void *field, unsigned size, unsigned precision, const char *fieldname)
  1412. {
  1413. if (checkForAttribute(fieldname))
  1414. outputXmlAttrUDecimal(field, size, precision, fieldname+1, out);
  1415. else
  1416. {
  1417. if (!nestLimit)
  1418. out.pad(indent);
  1419. outputEncodedXmlUDecimal(field, size, precision, fieldname, out);
  1420. if (!nestLimit)
  1421. out.newline();
  1422. }
  1423. }
  1424. void CommonEncodedXmlWriter::outputUnicode(unsigned len, const UChar *field, const char *fieldname)
  1425. {
  1426. if (flags & XWFtrim)
  1427. len = rtlTrimUnicodeStrLen(len, field);
  1428. if ((flags & XWFopt) && (rtlTrimUnicodeStrLen(len, field) == 0))
  1429. return;
  1430. if (checkForAttribute(fieldname))
  1431. outputXmlAttrUnicode(len, field, fieldname+1, out);
  1432. else
  1433. {
  1434. if (!nestLimit)
  1435. out.pad(indent);
  1436. outputEncodedXmlUnicode(len, field, fieldname, out);
  1437. if (!nestLimit)
  1438. out.newline();
  1439. }
  1440. }
  1441. void CommonEncodedXmlWriter::outputUtf8(unsigned len, const char *field, const char *fieldname)
  1442. {
  1443. if (flags & XWFtrim)
  1444. len = rtlTrimUtf8StrLen(len, field);
  1445. if ((flags & XWFopt) && (rtlTrimUtf8StrLen(len, field) == 0))
  1446. return;
  1447. if (checkForAttribute(fieldname))
  1448. outputXmlAttrUtf8(len, field, fieldname+1, out);
  1449. else
  1450. {
  1451. if (!nestLimit)
  1452. out.pad(indent);
  1453. outputEncodedXmlUtf8(len, field, fieldname, out);
  1454. if (!nestLimit)
  1455. out.newline();
  1456. }
  1457. }
  1458. //=====================================================================================
  1459. CommonEncoded64XmlWriter::CommonEncoded64XmlWriter(unsigned _flags, unsigned initialIndent, IXmlStreamFlusher *_flusher)
  1460. : CommonEncodedXmlWriter(_flags, initialIndent, _flusher)
  1461. {
  1462. }
  1463. void CommonEncoded64XmlWriter::outputData(unsigned len, const void *field, const char *fieldname)
  1464. {
  1465. if (checkForAttribute(fieldname))
  1466. outputXmlAttrData(len, field, fieldname+1, out);
  1467. else
  1468. {
  1469. if (!nestLimit)
  1470. out.pad(indent);
  1471. outputEncoded64XmlData(len, field, fieldname, out);
  1472. if (!nestLimit)
  1473. out.newline();
  1474. }
  1475. }
  1476. //=====================================================================================
  1477. CommonXmlWriter * CreateCommonXmlWriter(unsigned _flags, unsigned _initialIndent, IXmlStreamFlusher *_flusher, XMLWriterType xmlType)
  1478. {
  1479. switch (xmlType)
  1480. {
  1481. case WTStandard:
  1482. return new CommonXmlWriter(_flags, _initialIndent, _flusher);//standard XML writer
  1483. case WTEncodingData64:
  1484. return new CommonEncoded64XmlWriter(_flags, _initialIndent, _flusher);//writes xsd type attributes, and all data as base64binary
  1485. case WTEncoding:
  1486. return new CommonEncodedXmlWriter(_flags, _initialIndent, _flusher);//writes xsd type attributes, and all data as hexBinary
  1487. default:
  1488. assertex(false);
  1489. return NULL;
  1490. }
  1491. }
  1492. //=====================================================================================
  1493. IXmlWriterExt * createIXmlWriterExt(unsigned _flags, unsigned _initialIndent, IXmlStreamFlusher *_flusher, XMLWriterType xmlType)
  1494. {
  1495. if (xmlType==WTJSON)
  1496. return new CommonJsonWriter(_flags, _initialIndent, _flusher);
  1497. return CreateCommonXmlWriter(_flags, _initialIndent, _flusher, xmlType);
  1498. }
  1499. //=====================================================================================
  1500. SimpleOutputWriter::SimpleOutputWriter()
  1501. {
  1502. separatorNeeded = false;
  1503. }
  1504. void SimpleOutputWriter::outputFieldSeparator()
  1505. {
  1506. if (separatorNeeded)
  1507. out.append(',');
  1508. separatorNeeded = true;
  1509. }
  1510. SimpleOutputWriter & SimpleOutputWriter::clear()
  1511. {
  1512. out.clear();
  1513. separatorNeeded = false;
  1514. return *this;
  1515. }
  1516. void SimpleOutputWriter::outputQuoted(const char *text)
  1517. {
  1518. out.append(text);
  1519. }
  1520. void SimpleOutputWriter::outputString(unsigned len, const char *field, const char *)
  1521. {
  1522. outputFieldSeparator();
  1523. out.append(len, field);
  1524. }
  1525. void SimpleOutputWriter::outputQString(unsigned len, const char *field, const char *fieldname)
  1526. {
  1527. MemoryAttr tempBuffer;
  1528. char * temp;
  1529. if (len <= 100)
  1530. temp = (char *)alloca(len);
  1531. else
  1532. temp = (char *)tempBuffer.allocate(len);
  1533. rtlQStrToStr(len, temp, len, field);
  1534. outputString(len, temp, fieldname);
  1535. }
  1536. void SimpleOutputWriter::outputBool(bool field, const char *)
  1537. {
  1538. outputFieldSeparator();
  1539. outputXmlBool(field, NULL, out);
  1540. }
  1541. void SimpleOutputWriter::outputData(unsigned len, const void *field, const char *)
  1542. {
  1543. outputFieldSeparator();
  1544. outputXmlData(len, field, NULL, out);
  1545. }
  1546. void SimpleOutputWriter::outputInt(__int64 field, unsigned size, const char *)
  1547. {
  1548. outputFieldSeparator();
  1549. outputXmlInt(field, NULL, out);
  1550. }
  1551. void SimpleOutputWriter::outputUInt(unsigned __int64 field, unsigned size, const char *)
  1552. {
  1553. outputFieldSeparator();
  1554. outputXmlUInt(field, NULL, out);
  1555. }
  1556. void SimpleOutputWriter::outputReal(double field, const char *)
  1557. {
  1558. outputFieldSeparator();
  1559. outputXmlReal(field, NULL, out);
  1560. }
  1561. void SimpleOutputWriter::outputDecimal(const void *field, unsigned size, unsigned precision, const char *)
  1562. {
  1563. outputFieldSeparator();
  1564. outputXmlDecimal(field, size, precision, NULL, out);
  1565. }
  1566. void SimpleOutputWriter::outputUDecimal(const void *field, unsigned size, unsigned precision, const char *)
  1567. {
  1568. outputFieldSeparator();
  1569. outputXmlUDecimal(field, size, precision, NULL, out);
  1570. }
  1571. void SimpleOutputWriter::outputUnicode(unsigned len, const UChar *field, const char *)
  1572. {
  1573. outputFieldSeparator();
  1574. outputXmlUnicode(len, field, NULL, out);
  1575. }
  1576. void SimpleOutputWriter::outputUtf8(unsigned len, const char *field, const char *)
  1577. {
  1578. outputFieldSeparator();
  1579. outputXmlUtf8(len, field, NULL, out);
  1580. }
  1581. void SimpleOutputWriter::outputBeginNested(const char *s, bool)
  1582. {
  1583. if (!s || !*s)
  1584. return;
  1585. outputFieldSeparator();
  1586. out.append('[');
  1587. separatorNeeded = false;
  1588. }
  1589. void SimpleOutputWriter::outputEndNested(const char *s)
  1590. {
  1591. if (!s || !*s)
  1592. return;
  1593. out.append(']');
  1594. separatorNeeded = true;
  1595. }
  1596. void SimpleOutputWriter::outputSetAll()
  1597. {
  1598. out.append('*');
  1599. }
  1600. void SimpleOutputWriter::newline()
  1601. {
  1602. out.append('\n');
  1603. }
  1604. //=====================================================================================
  1605. CommonFieldProcessor::CommonFieldProcessor(StringBuffer &_result, bool _trim) : result(_result), trim(_trim)
  1606. {
  1607. }
  1608. void CommonFieldProcessor::processString(unsigned len, const char *value, const RtlFieldInfo * field)
  1609. {
  1610. if (trim)
  1611. len = rtlTrimStrLen(len, value);
  1612. result.append("'");
  1613. outputXmlString(len, value, NULL, result);
  1614. result.append("'");
  1615. }
  1616. void CommonFieldProcessor::processBool(bool value, const RtlFieldInfo * field)
  1617. {
  1618. outputXmlBool(value, NULL, result);
  1619. }
  1620. void CommonFieldProcessor::processData(unsigned len, const void *value, const RtlFieldInfo * field)
  1621. {
  1622. outputXmlData(len, value, NULL, result);
  1623. }
  1624. void CommonFieldProcessor::processInt(__int64 value, const RtlFieldInfo * field)
  1625. {
  1626. outputXmlInt(value, NULL, result);
  1627. }
  1628. void CommonFieldProcessor::processUInt(unsigned __int64 value, const RtlFieldInfo * field)
  1629. {
  1630. outputXmlUInt(value, NULL, result);
  1631. }
  1632. void CommonFieldProcessor::processReal(double value, const RtlFieldInfo * field)
  1633. {
  1634. outputXmlReal(value, NULL, result);
  1635. }
  1636. void CommonFieldProcessor::processDecimal(const void *value, unsigned digits, unsigned precision, const RtlFieldInfo * field)
  1637. {
  1638. outputXmlDecimal(value, digits, precision, NULL, result);
  1639. }
  1640. void CommonFieldProcessor::processUDecimal(const void *value, unsigned digits, unsigned precision, const RtlFieldInfo * field)
  1641. {
  1642. outputXmlUDecimal(value, digits, precision, NULL, result);
  1643. }
  1644. void CommonFieldProcessor::processUnicode(unsigned len, const UChar *value, const RtlFieldInfo * field)
  1645. {
  1646. if (trim)
  1647. len = rtlTrimUnicodeStrLen(len, value);
  1648. outputXmlUnicode(len, value, NULL, result);
  1649. }
  1650. void CommonFieldProcessor::processQString(unsigned len, const char *value, const RtlFieldInfo * field)
  1651. {
  1652. MemoryAttr tempBuffer;
  1653. char * temp;
  1654. if (len <= 100)
  1655. temp = (char *)alloca(len);
  1656. else
  1657. temp = (char *)tempBuffer.allocate(len);
  1658. rtlQStrToStr(len, temp, len, value);
  1659. processString(len, temp, field);
  1660. }
  1661. void CommonFieldProcessor::processUtf8(unsigned len, const char *value, const RtlFieldInfo * field)
  1662. {
  1663. if (trim)
  1664. len = rtlTrimUtf8StrLen(len, value);
  1665. outputXmlUtf8(len, value, NULL, result);
  1666. }
  1667. bool CommonFieldProcessor::processBeginSet(const RtlFieldInfo * field, unsigned numElements, bool isAll, const byte *data)
  1668. {
  1669. result.append('[');
  1670. if (isAll)
  1671. result.append("ALL");
  1672. return true;
  1673. }
  1674. bool CommonFieldProcessor::processBeginDataset(const RtlFieldInfo * field, unsigned numRows)
  1675. {
  1676. result.append('[');
  1677. return true;
  1678. }
  1679. bool CommonFieldProcessor::processBeginRow(const RtlFieldInfo * field)
  1680. {
  1681. result.append('{');
  1682. return true;
  1683. }
  1684. void CommonFieldProcessor::processEndSet(const RtlFieldInfo * field)
  1685. {
  1686. result.append(']');
  1687. }
  1688. void CommonFieldProcessor::processEndDataset(const RtlFieldInfo * field)
  1689. {
  1690. result.append(']');
  1691. }
  1692. void CommonFieldProcessor::processEndRow(const RtlFieldInfo * field)
  1693. {
  1694. result.append('}');
  1695. }
  1696. //=============================================================================================
  1697. void printKeyedValues(StringBuffer &out, IIndexReadContext *segs, IOutputMetaData *rowMeta)
  1698. {
  1699. unsigned totalKeyedSize = 0;
  1700. unsigned numSegs = segs->ordinality();
  1701. while (numSegs)
  1702. {
  1703. IKeySegmentMonitor &seg = *segs->item(numSegs-1);
  1704. if (!seg.isWild())
  1705. {
  1706. totalKeyedSize = seg.getOffset() + seg.getSize();
  1707. break;
  1708. }
  1709. numSegs--;
  1710. }
  1711. if (numSegs)
  1712. {
  1713. byte *tempRow = (byte *) alloca(totalKeyedSize);
  1714. byte *savedRow = (byte *) alloca(totalKeyedSize);
  1715. const RtlFieldInfo * const *fields = rowMeta->queryTypeInfo()->queryFields();
  1716. unsigned fieldOffset = 0;
  1717. bool inKeyed = false;
  1718. bool inWild = false;
  1719. for (unsigned segNo = 0; segNo < numSegs; segNo++)
  1720. {
  1721. IKeySegmentMonitor &seg = *segs->item(segNo);
  1722. unsigned segOffset = seg.getOffset();
  1723. unsigned segSize = seg.getSize();
  1724. while (fieldOffset < segOffset + segSize) // This is trying to cope with the combined case but not sure it completely does
  1725. {
  1726. assertex(fields[0]->type->isFixedSize());
  1727. unsigned curFieldSize = fields[0]->type->size(NULL, NULL);
  1728. if (seg.isWild())
  1729. {
  1730. if (!inWild)
  1731. {
  1732. if (inKeyed)
  1733. {
  1734. out.append("),");
  1735. inKeyed = false;
  1736. }
  1737. out.append("WILD(");
  1738. inWild = true;
  1739. }
  1740. else
  1741. out.append(',');
  1742. out.append(fields[0]->name);
  1743. }
  1744. else
  1745. {
  1746. StringBuffer setValues;
  1747. CommonFieldProcessor setProcessor(setValues, true);
  1748. unsigned numValues = 0;
  1749. unsigned subStringLength = 0;
  1750. if (!seg.isEmpty())
  1751. {
  1752. seg.setLow(tempRow);
  1753. for (;;)
  1754. {
  1755. if (numValues)
  1756. setValues.append(",");
  1757. memcpy(savedRow+segOffset, tempRow+segOffset, segSize);
  1758. seg.endRange(tempRow);
  1759. if (memcmp(savedRow+segOffset, tempRow+segOffset, segSize) != 0)
  1760. {
  1761. // Special case - if they differ only in trailing values that are 0 vs 0xff, then it's a substring match...
  1762. if (numValues==0 && (fields[0]->type->fieldType & (RFTMkind | RFTMebcdic)) == type_string)
  1763. {
  1764. unsigned pos;
  1765. for (pos = 0; pos < segSize; pos++)
  1766. {
  1767. if (savedRow[segOffset+pos] != tempRow[segOffset+pos])
  1768. break;
  1769. }
  1770. subStringLength = pos;
  1771. for (; pos < segSize; pos++)
  1772. {
  1773. if (savedRow[segOffset+pos] != 0 || tempRow[segOffset+pos] != 0xff)
  1774. {
  1775. subStringLength = 0;
  1776. break;
  1777. }
  1778. }
  1779. }
  1780. fields[0]->process(savedRow + fieldOffset, tempRow, setProcessor);
  1781. setValues.append("..");
  1782. fields[0]->process(tempRow + fieldOffset, tempRow, setProcessor);
  1783. numValues+=2;
  1784. }
  1785. else
  1786. {
  1787. fields[0]->process(tempRow + fieldOffset, tempRow, setProcessor);
  1788. numValues++;
  1789. }
  1790. if (!seg.increment(tempRow))
  1791. break;
  1792. }
  1793. }
  1794. if (!inKeyed)
  1795. {
  1796. if (inWild)
  1797. {
  1798. out.append("),");
  1799. inWild = false;
  1800. }
  1801. out.append("KEYED(");
  1802. inKeyed = true;
  1803. }
  1804. else
  1805. out.append(',');
  1806. out.append(fields[0]->name);
  1807. if (numValues==1)
  1808. out.append("=").append(setValues);
  1809. else if (subStringLength)
  1810. out.appendf("[1..%d]='", subStringLength).append(subStringLength, (char *) savedRow+fieldOffset).append("'");
  1811. else
  1812. out.append(" IN [").append(setValues).append("]");
  1813. }
  1814. fieldOffset += curFieldSize;
  1815. fields++;
  1816. if (!fields[0])
  1817. break;
  1818. }
  1819. }
  1820. if (inKeyed || inWild)
  1821. out.append(")");
  1822. }
  1823. else
  1824. out.append("UNKEYED");
  1825. }
  1826. extern thorhelper_decl void convertRowToXML(size32_t & lenResult, char * & result, IOutputMetaData & info, const void * row, unsigned flags)
  1827. {
  1828. const byte * self = (const byte *)row;
  1829. if (flags == (unsigned)-1)
  1830. flags = XWFtrim|XWFopt|XWFnoindent;
  1831. CommonXmlWriter writer(flags);
  1832. info.toXML(self, writer);
  1833. //could use detach...
  1834. unsigned sizeResult;
  1835. rtlStrToStrX(sizeResult, result, writer.length(), writer.str());
  1836. lenResult = rtlUtf8Length(sizeResult, result);
  1837. }
  1838. extern thorhelper_decl void convertRowToJSON(size32_t & lenResult, char * & result, IOutputMetaData & info, const void * row, unsigned flags)
  1839. {
  1840. const byte * self = (const byte *)row;
  1841. if (flags == (unsigned)-1)
  1842. flags = XWFtrim|XWFopt|XWFnoindent;
  1843. CommonJsonWriter writer(flags);
  1844. info.toXML(self, writer);
  1845. //could use detach...
  1846. unsigned sizeResult;
  1847. rtlStrToStrX(sizeResult, result, writer.length(), writer.str());
  1848. lenResult = rtlUtf8Length(sizeResult, result);
  1849. }