Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
5 : : * This Source Code Form is subject to the terms of the Mozilla Public
6 : : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
11 : : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : : * contributor license agreements. See the NOTICE file distributed
13 : : * with this work for additional information regarding copyright
14 : : * ownership. The ASF licenses this file to you under the Apache
15 : : * License, Version 2.0 (the "License"); you may not use this file
16 : : * except in compliance with the License. You may obtain a copy of
17 : : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : : */
19 : :
20 : : #include <stdio.h>
21 : : #include <resourcemodel/WW8ResourceModel.hxx>
22 : : #include <resourcemodel/TableManager.hxx>
23 : : #include <resourcemodel/QNameToString.hxx>
24 : : #include <resourcemodel/exceptions.hxx>
25 : : #include <resourcemodel/SubSequence.hxx>
26 : : #include <resourcemodel/util.hxx>
27 : : #include <resourcemodel.hxx>
28 : :
29 : : namespace writerfilter {
30 : :
31 : : class ResourceModelOutputWithDepth : public OutputWithDepth<string>
32 : : {
33 : : public:
34 : 20 : ResourceModelOutputWithDepth()
35 [ + - ][ + - ]: 20 : : OutputWithDepth<string>("<tablegroup>", "</tablegroup>") {}
[ + - ]
36 : :
37 [ + - ][ - + ]: 20 : ~ResourceModelOutputWithDepth() {outputGroup();}
38 : :
39 : 0 : void output(const string & str) const { cout << str << endl; }
40 : : };
41 : :
42 : 20 : ResourceModelOutputWithDepth output;
43 : :
44 : 0 : Stream::Pointer_t createStreamHandler()
45 : : {
46 [ # # ]: 0 : return Stream::Pointer_t(new WW8StreamHandler());
47 : : }
48 : :
49 : 0 : void dump(OutputWithDepth<string> & /*o*/, const char * /*name*/,
50 : : writerfilter::Reference<Properties>::Pointer_t /*props*/)
51 : : {
52 : 0 : }
53 : :
54 : 0 : void dump(OutputWithDepth<string> & o, const char * name, sal_uInt32 n)
55 : : {
56 : : char sBuffer[256];
57 : 0 : snprintf(sBuffer, sizeof(sBuffer), "%" SAL_PRIuUINT32, n);
58 [ # # ]: 0 : string tmpStr = name;
59 [ # # ]: 0 : tmpStr += "=";
60 [ # # ]: 0 : tmpStr += sBuffer;
61 : :
62 [ # # ]: 0 : o.addItem(tmpStr);
63 : 0 : }
64 : :
65 : 0 : void dump(OutputWithDepth<string> & /*o*/, const char * /*name*/,
66 : : const OUString & /*str*/)
67 : : {
68 : 0 : }
69 : :
70 : 0 : void dump(OutputWithDepth<string> & /*o*/, const char * /*name*/,
71 : : writerfilter::Reference<BinaryObj>::Pointer_t /*binary*/)
72 : : {
73 : 0 : }
74 : :
75 [ + - ]: 20 : string gInfo = "";
76 : : // ------- WW8TableDataHandler ---------
77 : :
78 : : class TablePropsRef : public writerfilter::Reference<Properties>
79 : : {
80 : : public:
81 : : typedef boost::shared_ptr<TablePropsRef> Pointer_t;
82 : :
83 : : TablePropsRef() {}
84 [ # # ]: 0 : virtual ~TablePropsRef() {}
85 : :
86 : 0 : virtual void resolve(Properties & /*rHandler*/) {}
87 : :
88 [ # # ]: 0 : virtual string getType() const { return "TableProps"; }
89 : : void reset() {}
90 : 0 : void insert(Pointer_t /* pTablePropsRef */) {}
91 : : };
92 : :
93 : : typedef TablePropsRef::Pointer_t TablePropsRef_t;
94 : :
95 : 0 : class WW8TableDataHandler : public TableDataHandler<string,
96 : : TablePropsRef_t>
97 : : {
98 : : public:
99 [ # # ]: 0 : virtual ~WW8TableDataHandler() {}
100 : :
101 : : typedef boost::shared_ptr<WW8TableDataHandler> Pointer_t;
102 : : virtual void startTable(unsigned int nRows, unsigned int nDepth,
103 : : TablePropsRef_t pProps);
104 : : virtual void endTable();
105 : : virtual void startRow(unsigned int nCols,
106 : : TablePropsRef_t pProps);
107 : : virtual void endRow();
108 : : virtual void startCell(const string & start, TablePropsRef_t pProps);
109 : : virtual void endCell(const string & end);
110 : : };
111 : :
112 : 0 : void WW8TableDataHandler::startTable(unsigned int nRows, unsigned int nDepth,
113 : : TablePropsRef_t /*pProps*/)
114 : : {
115 : : char sBuffer[256];
116 : :
117 [ # # ]: 0 : string tmpStr = "<tabledata.table rows=\"";
118 : 0 : snprintf(sBuffer, sizeof(sBuffer), "%d", nRows);
119 [ # # ]: 0 : tmpStr += sBuffer;
120 [ # # ]: 0 : tmpStr += "\" depth=\"";
121 : 0 : snprintf(sBuffer, sizeof(sBuffer), "%d", nDepth);
122 [ # # ]: 0 : tmpStr += sBuffer;
123 [ # # ]: 0 : tmpStr += "\">";
124 : :
125 [ # # ]: 0 : output.addItem(tmpStr);
126 : 0 : }
127 : :
128 : 0 : void WW8TableDataHandler::endTable()
129 : : {
130 [ # # ][ # # ]: 0 : output.addItem("</tabledata.table>");
131 : 0 : }
132 : :
133 : 0 : void WW8TableDataHandler::startRow
134 : : (unsigned int nCols, TablePropsRef_t /*pProps*/)
135 : : {
136 : : char sBuffer[256];
137 : :
138 : 0 : snprintf(sBuffer, sizeof(sBuffer), "%d", nCols);
139 [ # # ]: 0 : string tmpStr = "<tabledata.row cells=\"";
140 [ # # ]: 0 : tmpStr += sBuffer;
141 [ # # ]: 0 : tmpStr += "\">";
142 [ # # ]: 0 : output.addItem(tmpStr);
143 : 0 : }
144 : :
145 : 0 : void WW8TableDataHandler::endRow()
146 : : {
147 [ # # ][ # # ]: 0 : output.addItem("</tabledata.row>");
148 : 0 : }
149 : :
150 : 0 : void WW8TableDataHandler::startCell(const string & start,
151 : : TablePropsRef_t /*pProps*/)
152 : : {
153 [ # # ][ # # ]: 0 : output.addItem("<tabledata.cell>");
154 : 0 : output.addItem(start);
155 [ # # ][ # # ]: 0 : output.addItem(", ");
156 : 0 : }
157 : :
158 : 0 : void WW8TableDataHandler::endCell(const string & end)
159 : : {
160 : 0 : output.addItem(end);
161 [ # # ][ # # ]: 0 : output.addItem("</tabledata.cell>");
162 : 0 : }
163 : :
164 : : // ----- WW8TableDataManager -------------------------------
165 : :
166 : : class WW8TableManager :
167 : : public TableManager<string, TablePropsRef_t>
168 : : {
169 : : typedef TableDataHandler<string, TablePropsRef_t>
170 : : TableDataHandlerPointer_t;
171 : :
172 : : public:
173 : : WW8TableManager();
174 [ # # ]: 0 : virtual ~WW8TableManager() {}
175 : : virtual void endParagraphGroup();
176 : : virtual bool sprm(Sprm & rSprm);
177 : : };
178 : :
179 : 0 : WW8TableManager::WW8TableManager()
180 : : {
181 [ # # ][ # # ]: 0 : TableDataHandler<string, TablePropsRef_t>::Pointer_t pHandler(new WW8TableDataHandler());
[ # # ]
182 [ # # ][ # # ]: 0 : setHandler(pHandler);
[ # # ][ # # ]
183 : 0 : }
184 : :
185 : 0 : bool WW8TableManager::sprm(Sprm & rSprm)
186 : : {
187 : 0 : TableManager<string, TablePropsRef_t>::sprm(rSprm);
188 : 0 : output.setDepth(getTableDepthNew());
189 : 0 : return true;
190 : : }
191 : :
192 : 0 : void WW8TableManager::endParagraphGroup()
193 : : {
194 [ # # ]: 0 : string tmpStr = "<tabledepth depth=\"";
195 : : char sBuffer[256];
196 : 0 : snprintf(sBuffer, sizeof(sBuffer), "%" SAL_PRIuUINT32, getTableDepthNew());
197 [ # # ]: 0 : tmpStr += sBuffer;
198 [ # # ]: 0 : tmpStr += "\"/>";
199 [ # # ]: 0 : output.addItem(tmpStr);
200 [ # # ]: 0 : TableManager<string, TablePropsRef_t>::endParagraphGroup();
201 : 0 : }
202 : :
203 : : /* WW8StreamHandler */
204 : :
205 : 0 : WW8StreamHandler::WW8StreamHandler()
206 : 0 : : mnUTextCount(0)
207 : : {
208 [ # # ]: 0 : output.closeGroup();
209 [ # # ][ # # ]: 0 : output.addItem("<stream>");
210 [ # # ][ # # ]: 0 : mpTableManager = new WW8TableManager;
211 [ # # ]: 0 : mpTableManager->startLevel();
212 : 0 : }
213 : :
214 : 0 : WW8StreamHandler::~WW8StreamHandler()
215 : : {
216 [ # # ]: 0 : mpTableManager->endLevel();
217 [ # # ][ # # ]: 0 : delete mpTableManager;
218 : :
219 [ # # ]: 0 : output.closeGroup();
220 [ # # ][ # # ]: 0 : output.addItem("</stream>");
221 [ # # ]: 0 : }
222 : :
223 : 0 : void WW8StreamHandler::startSectionGroup()
224 : : {
225 [ # # ][ # # ]: 0 : output.addItem("<section-group>");
226 : 0 : }
227 : :
228 : 0 : void WW8StreamHandler::endSectionGroup()
229 : : {
230 [ # # ][ # # ]: 0 : output.addItem("</section-group>");
231 : 0 : }
232 : :
233 : 0 : void WW8StreamHandler::startParagraphGroup()
234 : : {
235 : 0 : output.openGroup();
236 [ # # ][ # # ]: 0 : output.addItem("<paragraph-group>");
237 : :
238 : 0 : mpTableManager->startParagraphGroup();
239 : 0 : mpTableManager->handle(gInfo);
240 : 0 : }
241 : :
242 : 0 : void WW8StreamHandler::endParagraphGroup()
243 : : {
244 : 0 : mpTableManager->endParagraphGroup();
245 : :
246 [ # # ][ # # ]: 0 : output.addItem("</paragraph-group>");
247 : 0 : output.closeGroup();
248 : :
249 : 0 : }
250 : :
251 : 0 : void WW8StreamHandler::startCharacterGroup()
252 : : {
253 [ # # ][ # # ]: 0 : output.addItem("<character-group>");
254 : 0 : }
255 : :
256 : 0 : void WW8StreamHandler::endCharacterGroup()
257 : : {
258 [ # # ][ # # ]: 0 : output.addItem("</character-group>");
259 : 0 : }
260 : :
261 : 0 : void WW8StreamHandler::startShape( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > /*xShape*/ )
262 : : {
263 [ # # ][ # # ]: 0 : output.addItem("<shape>");
264 : 0 : }
265 : :
266 : 0 : void WW8StreamHandler::endShape( )
267 : : {
268 [ # # ][ # # ]: 0 : output.addItem( "</shape>" );
269 : 0 : }
270 : :
271 : 0 : void WW8StreamHandler::text(const sal_uInt8 * data, size_t len)
272 : : {
273 [ # # ]: 0 : string tmpStr = "<text>";
274 : :
275 [ # # ]: 0 : for (unsigned int n = 0; n < len; ++n)
276 : : {
277 [ # # # # ]: 0 : switch (static_cast<unsigned char>(data[n]))
278 : : {
279 : : case '<':
280 [ # # ]: 0 : tmpStr += "<";
281 : :
282 : 0 : break;
283 : : case '>':
284 [ # # ]: 0 : tmpStr += ">";
285 : :
286 : 0 : break;
287 : :
288 : : case '&':
289 [ # # ]: 0 : tmpStr += "&";
290 : :
291 : 0 : break;
292 : : default:
293 [ # # ]: 0 : if (isprint(data[n]))
294 [ # # ]: 0 : tmpStr += static_cast<char>(data[n]);
295 : : else
296 : : {
297 : : char sBuffer[256];
298 : :
299 : 0 : snprintf(sBuffer, sizeof(sBuffer), "\\0x%02x", data[n]);
300 : :
301 [ # # ]: 0 : tmpStr += sBuffer;
302 : : }
303 : : }
304 : : }
305 : :
306 [ # # ]: 0 : tmpStr += "</text>";
307 : :
308 [ # # ]: 0 : output.addItem(tmpStr);
309 : :
310 [ # # ]: 0 : mpTableManager->text(data, len);
311 : 0 : }
312 : :
313 : 0 : void WW8StreamHandler::utext(const sal_uInt8 * data, size_t len)
314 : : {
315 : : static char sBuffer[256];
316 : 0 : snprintf(sBuffer, sizeof(sBuffer), "<utext count=\"%d\">", mnUTextCount);
317 [ # # ]: 0 : string tmpStr(sBuffer);
318 : :
319 [ # # ]: 0 : for (unsigned int n = 0; n < len; ++n)
320 : : {
321 : 0 : sal_Unicode nChar = data[n * 2] + (data[n * 2 + 1] << 8);
322 [ # # ][ # # ]: 0 : if (nChar < 0xff && isprint(nChar))
323 : : {
324 [ # # # # ]: 0 : switch (nChar)
325 : : {
326 : : case '&':
327 [ # # ]: 0 : tmpStr += "&";
328 : 0 : break;
329 : : case '<':
330 [ # # ]: 0 : tmpStr += "<";
331 : 0 : break;
332 : : case '>':
333 [ # # ]: 0 : tmpStr += ">";
334 : 0 : break;
335 : : default:
336 [ # # ]: 0 : tmpStr += static_cast<char>(nChar);
337 : : }
338 : : }
339 : : else
340 : : {
341 : 0 : snprintf(sBuffer, sizeof(sBuffer), "\\0x%04x", nChar);
342 : :
343 [ # # ]: 0 : tmpStr += sBuffer;
344 : : }
345 : : }
346 : :
347 [ # # ]: 0 : tmpStr += "</utext>";
348 : :
349 [ # # ]: 0 : output.addItem(tmpStr);
350 : :
351 [ # # ]: 0 : mpTableManager->utext(data, len);
352 : :
353 : 0 : mnUTextCount++;
354 : 0 : }
355 : :
356 : 0 : void WW8StreamHandler::props(writerfilter::Reference<Properties>::Pointer_t ref)
357 : : {
358 [ # # ]: 0 : WW8PropertiesHandler aHandler(mpTableManager);
359 : :
360 [ # # ][ # # ]: 0 : output.addItem("<properties type=\"" + ref->getType() + "\">");
[ # # ][ # # ]
361 [ # # ]: 0 : ref->resolve(aHandler);
362 : :
363 : : //mpTableManager->props(ref);
364 : :
365 [ # # ][ # # ]: 0 : output.addItem("</properties>");
366 : 0 : }
367 : :
368 : 0 : void WW8StreamHandler::table(Id name, writerfilter::Reference<Table>::Pointer_t ref)
369 : : {
370 : 0 : WW8TableHandler aHandler(mpTableManager);
371 : :
372 [ # # ][ # # ]: 0 : output.addItem("<table id=\"" + (*QNameToString::Instance())(name)
373 [ # # ][ # # ]: 0 : + "\">");
[ # # ][ # # ]
374 : :
375 : : try
376 : : {
377 [ # # ]: 0 : ref->resolve(aHandler);
378 : : }
379 [ # # # # ]: 0 : catch (const Exception &e)
380 : : {
381 [ # # # # : 0 : output.addItem("<exception>" + e.getText() + "</exception>");
# # ]
382 : : }
383 : :
384 [ # # ][ # # ]: 0 : output.addItem("</table>");
385 : 0 : }
386 : :
387 : 0 : void WW8StreamHandler::substream(Id name,
388 : : writerfilter::Reference<Stream>::Pointer_t ref)
389 : : {
390 : 0 : output.addItem("<substream name=\"" + (*QNameToString::Instance())(name)
391 [ # # ][ # # ]: 0 : + "\">");
[ # # ][ # # ]
392 : :
393 : 0 : mpTableManager->startLevel();
394 : :
395 : 0 : ref->resolve(*this);
396 : :
397 : 0 : mpTableManager->endLevel();
398 : :
399 [ # # ][ # # ]: 0 : output.addItem("</substream>");
400 : 0 : }
401 : :
402 : 0 : void WW8StreamHandler::info(const string & info_)
403 : : {
404 : 0 : gInfo = info_;
405 [ # # ][ # # ]: 0 : output.addItem("<info>" + info_ + "</info>");
406 : 0 : }
407 : :
408 : 0 : void WW8PropertiesHandler::attribute(Id name, Value & val)
409 : : {
410 [ # # ][ # # ]: 0 : boost::shared_ptr<OString> pStr(new OString());
411 [ # # ]: 0 : OUString aStr = val.getString();
412 : : aStr.convertToString(pStr.get(), RTL_TEXTENCODING_ASCII_US,
413 : 0 : OUSTRING_TO_OSTRING_CVTFLAGS);
414 [ # # ][ # # ]: 0 : string sXMLValue = xmlify(pStr->getStr());
415 : :
416 : : char sBuffer[256];
417 [ # # ]: 0 : snprintf(sBuffer, sizeof(sBuffer), "0x%x", val.getInt());
418 : :
419 : : output.addItem("<attribute name=\"" +
420 [ # # ][ # # ]: 0 : (*QNameToString::Instance())(name) +
421 : : "\" value=\"" +
422 : : sXMLValue +
423 : : + "\" hexvalue=\""
424 [ # # ][ # # ]: 0 : + sBuffer + "\">");
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
425 : :
426 [ # # ]: 0 : writerfilter::Reference<Properties>::Pointer_t pProps = val.getProperties();
427 : :
428 [ # # ]: 0 : if (pProps.get() != NULL)
429 : : {
430 : : output.addItem("<properties name=\"" +
431 [ # # ][ # # ]: 0 : (*QNameToString::Instance())(name)
432 [ # # # # ]: 0 : + "\" type=\"" + pProps->getType() + "\">");
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
433 : :
434 : : try
435 : : {
436 [ # # ]: 0 : pProps->resolve(*this);
437 : : }
438 [ # # ]: 0 : catch (const ExceptionOutOfBounds &)
439 : : {
440 : : }
441 : :
442 [ # # ][ # # ]: 0 : output.addItem("</properties>");
443 : : }
444 : :
445 [ # # ]: 0 : writerfilter::Reference<Stream>::Pointer_t pStream = val.getStream();
446 : :
447 [ # # ]: 0 : if (pStream.get() != NULL)
448 : : {
449 : : try
450 : : {
451 [ # # ]: 0 : WW8StreamHandler aHandler;
452 : :
453 [ # # ][ # # ]: 0 : pStream->resolve(aHandler);
[ # # ]
454 : : }
455 [ # # ]: 0 : catch (const ExceptionOutOfBounds &)
456 : : {
457 : : }
458 : : }
459 : :
460 [ # # ]: 0 : writerfilter::Reference<BinaryObj>::Pointer_t pBinObj = val.getBinary();
461 : :
462 [ # # ]: 0 : if (pBinObj.get() != NULL)
463 : : {
464 : : try
465 : : {
466 : 0 : WW8BinaryObjHandler aHandler;
467 : :
468 [ # # ][ # # ]: 0 : pBinObj->resolve(aHandler);
469 : : }
470 [ # # ]: 0 : catch (const ExceptionOutOfBounds &)
471 : : {
472 : : }
473 : : }
474 : :
475 [ # # ][ # # ]: 0 : output.addItem("</attribute>");
[ # # ][ # # ]
[ # # ][ # # ]
476 : 0 : }
477 : :
478 : 0 : void WW8PropertiesHandler::sprm(Sprm & sprm_)
479 : : {
480 [ # # ]: 0 : string tmpStr = "<sprm id=\"";
481 : : char buffer[256];
482 [ # # ]: 0 : snprintf(buffer, sizeof(buffer), "0x%" SAL_PRIxUINT32, sprm_.getId());
483 [ # # ]: 0 : tmpStr += buffer;
484 [ # # ]: 0 : tmpStr += "\" name=\"";
485 [ # # ][ # # ]: 0 : tmpStr += sprm_.getName();
486 [ # # ]: 0 : tmpStr += "\">";
487 [ # # ]: 0 : output.addItem(tmpStr);
488 [ # # ][ # # ]: 0 : output.addItem(sprm_.toString());
489 : :
490 [ # # ]: 0 : writerfilter::Reference<Properties>::Pointer_t pProps = sprm_.getProps();
491 : :
492 [ # # ]: 0 : if (pProps.get() != NULL)
493 : : {
494 [ # # ][ # # ]: 0 : output.addItem("<properties type=\"" + pProps->getType() + "\">");
[ # # ][ # # ]
495 [ # # ]: 0 : pProps->resolve(*this);
496 [ # # ][ # # ]: 0 : output.addItem("</properties>");
497 : : }
498 : :
499 [ # # ]: 0 : writerfilter::Reference<BinaryObj>::Pointer_t pBinObj = sprm_.getBinary();
500 : :
501 [ # # ]: 0 : if (pBinObj.get() != NULL)
502 : : {
503 [ # # ][ # # ]: 0 : output.addItem("<binary>");
504 : 0 : WW8BinaryObjHandler aHandler;
505 [ # # ]: 0 : pBinObj->resolve(aHandler);
506 [ # # ][ # # ]: 0 : output.addItem("</binary>");
507 : : }
508 : :
509 [ # # ]: 0 : writerfilter::Reference<Stream>::Pointer_t pStream = sprm_.getStream();
510 : :
511 [ # # ]: 0 : if (pStream.get() != NULL)
512 : : {
513 [ # # ][ # # ]: 0 : output.addItem("<stream>");
514 [ # # ]: 0 : WW8StreamHandler aHandler;
515 [ # # ]: 0 : pStream->resolve(aHandler);
516 [ # # ][ # # ]: 0 : output.addItem("</stream>");
[ # # ]
517 : : }
518 : :
519 [ # # ]: 0 : mpTableManager->sprm(sprm_);
520 : :
521 [ # # ][ # # ]: 0 : output.addItem("</sprm>");
[ # # ][ # # ]
[ # # ]
522 : 0 : }
523 : :
524 : 0 : void WW8TableHandler::entry(int /*pos*/,
525 : : writerfilter::Reference<Properties>::Pointer_t ref)
526 : : {
527 [ # # ][ # # ]: 0 : output.addItem("<tableentry>");
528 : :
529 [ # # ]: 0 : WW8PropertiesHandler aHandler(mpTableManager);
530 : :
531 : : try
532 : : {
533 [ # # ]: 0 : ref->resolve(aHandler);
534 : : }
535 [ # # ]: 0 : catch (const Exception &e)
536 : : {
537 [ # # # # : 0 : output.addItem("<exception>" + e.getText() + "</exception>");
# # ]
538 [ # # # # ]: 0 : output.addItem("</tableentry>");
539 : :
540 : 0 : throw;
541 : : }
542 : :
543 [ # # ][ # # ]: 0 : output.addItem("</tableentry>");
544 : 0 : }
545 : :
546 : 0 : void WW8BinaryObjHandler::data
547 : : (const sal_uInt8 * buf, size_t length,
548 : : writerfilter::Reference<Properties>::Pointer_t /*pRef*/)
549 : : {
550 [ # # ]: 0 : SubSequence<sal_uInt8> aSeq(buf, length);
551 : :
552 [ # # ][ # # ]: 0 : aSeq.dump(output);
553 : 0 : }
554 : :
555 [ + - ][ + - ]: 60 : }
556 : :
557 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|