TextUtilities.Mod 78 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576
  1. MODULE TextUtilities; (** AUTHOR "TF"; PURPOSE "Utilities for the Unicode text system"; *)
  2. IMPORT
  3. SYSTEM, (* for Oberon Text colors *)
  4. Configuration, Commands, Codecs, FP1616,
  5. KernelLog, Texts, Streams, Files, UTF8Strings, XML, XMLScanner, XMLParser, XMLObjects, Repositories, Strings, WMGraphics,
  6. UnicodeProperties;
  7. CONST
  8. Ok* = 0;
  9. FileNotFound* = Files.FileNotFound;
  10. FileCreationError* = 2;
  11. CodecNotFound* = 3;
  12. CR = 0DX; LF = 0AX; TAB = 09X;
  13. (** FormatDescriptor features *)
  14. LoadUnicode* = 0;
  15. StoreUnicode* = 1;
  16. LoadFormated* = 2;
  17. StoreFormatted* = 3;
  18. BufferedAttributes=256; (* number of attributes buffered before updates must take place *)
  19. TYPE
  20. Char32 = Texts.Char32;
  21. Text = Texts.Text;
  22. LoaderProc* = PROCEDURE {DELEGATE} (text : Text; filename : ARRAY OF CHAR; VAR res : WORD);
  23. TYPE
  24. FormatDescriptor = OBJECT
  25. VAR name : Strings.String;
  26. loadProc, storeProc : Strings.String;
  27. END FormatDescriptor;
  28. AttributesBuf*=RECORD
  29. attributes: POINTER TO ARRAY OF Texts.Attributes;
  30. positions: POINTER TO ARRAY OF LONGINT;
  31. length: LONGINT;
  32. END;
  33. TextWriter* = OBJECT (Streams.Writer);
  34. VAR text : Texts.Text;
  35. ucs32buf : POINTER TO ARRAY OF LONGINT;
  36. fontName : ARRAY 32 OF CHAR;
  37. fontSize, x, fontVOff : LONGINT; fontColor, fontBgColor: WMGraphics.Color;
  38. fontStyle : SET;
  39. currentAttributes- : Texts.Attributes;
  40. oldBytes : ARRAY 7 OF CHAR;
  41. nofOldBytes : LONGINT;
  42. attributesBuf: AttributesBuf;
  43. PROCEDURE &Init*(text : Texts.Text);
  44. BEGIN
  45. SELF.text := text;
  46. nofOldBytes := 0;
  47. currentAttributes := GetDefaultAttributes();
  48. fontColor := currentAttributes.color;
  49. fontBgColor := currentAttributes.bgcolor;
  50. fontVOff := currentAttributes.voff;
  51. COPY(currentAttributes.fontInfo.name, fontName);
  52. fontSize := currentAttributes.fontInfo.size;
  53. fontStyle := currentAttributes.fontInfo.style;
  54. NEW(attributesBuf.attributes,BufferedAttributes);
  55. NEW(attributesBuf.positions,BufferedAttributes);
  56. attributesBuf.length := 0;
  57. InitWriter (Add, 128 * 1024);
  58. END Init;
  59. PROCEDURE Add(CONST buf: ARRAY OF CHAR; ofs, len: LONGINT; propagate: BOOLEAN; VAR res: WORD);
  60. VAR
  61. p, i, idx, pos : LONGINT;
  62. nextAttribute: LONGINT;
  63. pieceOffset, pieceLength: LONGINT;
  64. nextAttributes: Texts.Attributes;
  65. BEGIN
  66. pieceOffset := ofs; pieceLength := len;
  67. IF (ucs32buf = NIL) OR (pieceLength >= LEN(ucs32buf)) THEN NEW(ucs32buf, pieceLength + 1) END;
  68. p := pieceOffset; idx := 0;
  69. (* complete an unfinished character *)
  70. IF nofOldBytes > 0 THEN
  71. FOR i := nofOldBytes TO ORD(UTF8Strings.CodeLength[ORD(oldBytes[0])]) - 1 DO
  72. oldBytes[i] := buf[p]; INC(p)
  73. END;
  74. i := 0; IF UTF8Strings.DecodeChar(oldBytes, i, ucs32buf[idx]) THEN INC(idx) END;
  75. nofOldBytes := 0
  76. END;
  77. WHILE (p < pieceOffset + pieceLength) & (ORD(UTF8Strings.CodeLength[ORD(buf[p])]) <= pieceOffset+pieceLength) &
  78. UTF8Strings.DecodeChar(buf, p, ucs32buf[idx]) DO INC(idx) END;
  79. ucs32buf[idx] := 0;
  80. IF (p < pieceOffset + pieceLength) & (ORD(UTF8Strings.CodeLength[ORD(buf[p])]) >= pieceOffset+pieceLength) THEN (* could not be decoded because of missing bytes. ignore other problems *)
  81. WHILE p < pieceOffset+pieceLength DO oldBytes[i] := buf[p]; INC(p); INC(i) END;
  82. nofOldBytes := i;
  83. KernelLog.String("Update within UTF sequence "); KernelLog.Ln;
  84. END;
  85. IF len > 0 THEN
  86. text.AcquireWrite;
  87. pos := text.GetLength();
  88. text.InsertUCS32(text.GetLength(), ucs32buf^);
  89. pieceOffset := 0; nextAttribute := 0;
  90. WHILE nextAttribute < attributesBuf.length DO
  91. nextAttributes := attributesBuf.attributes[nextAttribute];
  92. pieceLength:= attributesBuf.positions[nextAttribute]-pieceOffset;
  93. text.SetAttributes(pos+pieceOffset,pieceLength,currentAttributes);
  94. INC(pieceOffset, pieceLength);
  95. currentAttributes := nextAttributes;
  96. INC(nextAttribute);
  97. END;
  98. text.SetAttributes(pieceOffset+pos, text.GetLength()-pos-pieceOffset, currentAttributes);
  99. text.ReleaseWrite;
  100. attributesBuf.length := 0;
  101. END;
  102. END Add;
  103. (** Write end-of-line character *)
  104. PROCEDURE Ln*; (** overwrite Ln^ *)
  105. BEGIN
  106. Char(CHR(Texts.NewLineChar));
  107. END Ln;
  108. PROCEDURE SetAttributes*(attributes: Texts.Attributes);
  109. VAR i: LONGINT;
  110. BEGIN
  111. IF attributesBuf.length = LEN(attributesBuf.attributes) THEN Update(); END;
  112. i := attributesBuf.length;
  113. attributesBuf.attributes[i] := attributes;
  114. attributesBuf.positions[i] := Pos()-sent;
  115. INC(i);
  116. attributesBuf.length := i;
  117. END SetAttributes;
  118. PROCEDURE NewAttributes(): Texts.Attributes;
  119. VAR attributes: Texts.Attributes;
  120. BEGIN
  121. NEW(attributes); attributes.Set(fontColor, fontBgColor, fontVOff, fontName, fontSize, fontStyle);
  122. RETURN attributes
  123. END NewAttributes;
  124. PROCEDURE SetFontName* (CONST name : ARRAY OF CHAR);
  125. BEGIN
  126. COPY(name, fontName);
  127. SetAttributes(NewAttributes());
  128. END SetFontName;
  129. PROCEDURE SetFontSize* (size : LONGINT);
  130. BEGIN
  131. fontSize := size;
  132. SetAttributes(NewAttributes());
  133. END SetFontSize;
  134. PROCEDURE SetFontStyle* (style : SET);
  135. BEGIN
  136. fontStyle := style;
  137. SetAttributes(NewAttributes());
  138. END SetFontStyle;
  139. PROCEDURE SetFontColor* (color : WMGraphics.Color);
  140. BEGIN
  141. fontColor := color;
  142. SetAttributes(NewAttributes());
  143. END SetFontColor;
  144. PROCEDURE SetBgColor* (bgColor : LONGINT);
  145. BEGIN
  146. fontBgColor := bgColor;
  147. SetAttributes(NewAttributes());
  148. END SetBgColor;
  149. PROCEDURE SetVerticalOffset* (voff : LONGINT);
  150. BEGIN
  151. fontVOff := voff;
  152. SetAttributes(NewAttributes());
  153. END SetVerticalOffset;
  154. PROCEDURE AddObject*(obj : ANY);
  155. VAR op : Texts.ObjectPiece;
  156. BEGIN
  157. Update;
  158. NEW(op); op.object := obj;
  159. text.AcquireWrite;
  160. text.InsertPiece(text.GetLength(), op);
  161. text.ReleaseWrite;
  162. END AddObject;
  163. END TextWriter;
  164. TextReader* = OBJECT (Streams.Reader)
  165. VAR
  166. reader: Texts.TextReader;
  167. remainder: LONGINT;
  168. PROCEDURE &Init*(text : Texts.Text);
  169. BEGIN
  170. remainder := 0;
  171. NEW (reader, text);
  172. InitReader (Receive, Streams.DefaultReaderSize);
  173. END Init;
  174. PROCEDURE Receive (VAR buf: ARRAY OF CHAR; ofs, size, min: LONGINT; VAR len: LONGINT; VAR res: WORD);
  175. VAR ucs32, prevofs: LONGINT;
  176. BEGIN
  177. reader.text.AcquireRead;
  178. len := 0; res := Streams.Ok;
  179. WHILE len < size DO
  180. IF remainder # 0 THEN
  181. ucs32 := remainder; remainder := 0;
  182. ELSE
  183. reader.ReadCh (ucs32);
  184. END;
  185. prevofs := ofs;
  186. IF (ucs32 = 0) OR ~UTF8Strings.EncodeChar (ucs32, buf, ofs) THEN
  187. remainder := ucs32;
  188. IF len < min THEN res := Streams.EOF END;
  189. reader.text.ReleaseRead;
  190. RETURN
  191. END;
  192. INC (len, ofs - prevofs);
  193. END;
  194. reader.text.ReleaseRead;
  195. END Receive;
  196. PROCEDURE CanSetPos*() : BOOLEAN;
  197. BEGIN
  198. RETURN TRUE;
  199. END CanSetPos;
  200. PROCEDURE SetPos*(pos: Streams.Position);
  201. BEGIN
  202. reader.text.AcquireRead;
  203. reader.SetPosition(pos); (* pos is clipped *)
  204. received := reader.GetPosition(); (* this effects that Streams.Reader.Pos() returns the correct location in the text *)
  205. Reset;
  206. remainder := 0;
  207. reader.text.ReleaseRead;
  208. END SetPos;
  209. END TextReader;
  210. TYPE
  211. LongintArray = POINTER TO ARRAY OF LONGINT;
  212. Operation = RECORD op, pos, len : LONGINT END;
  213. Operations = POINTER TO ARRAY OF Operation;
  214. TextSelection*=OBJECT
  215. VAR text* : Texts.Text;
  216. from*, to* : Texts.TextPosition;
  217. END TextSelection;
  218. TextPositionKeeper* = OBJECT(Texts.TextPosition);
  219. VAR positions : LongintArray;
  220. nofPositions : LONGINT;
  221. operations : Operations;
  222. nofOperations, nofDeleted : LONGINT;
  223. PROCEDURE &New*(t : Texts.Text);
  224. BEGIN
  225. New^(t);
  226. NEW(positions, 256); NEW(operations, 256);
  227. nofOperations := 0; nofPositions := 0; nofDeleted := 0
  228. END New;
  229. PROCEDURE GrowOperations;
  230. VAR i : LONGINT;
  231. t : Operations;
  232. BEGIN
  233. NEW(t, nofOperations * 2);
  234. FOR i := 0 TO nofOperations - 1 DO t[i] := operations[i] END;
  235. operations := t
  236. END GrowOperations;
  237. PROCEDURE Cleanup;
  238. VAR i, j, p, op, pos : LONGINT;
  239. BEGIN
  240. IF nofOperations = 0 THEN RETURN END;
  241. FOR i := 0 TO nofPositions - 1 DO
  242. p := positions[i];
  243. IF p >= 0 THEN
  244. FOR j := 0 TO nofOperations - 1 DO
  245. op := operations[j].op; pos := operations[j].pos;
  246. IF (p >= pos) & (op = Texts.OpInsert) THEN INC(p, operations[j].len)
  247. ELSIF (p >= pos) & (p <= pos + operations[j].len) & (op = Texts.OpDelete) THEN p := pos
  248. ELSIF (p > pos) & (op = Texts.OpDelete) THEN DEC(p, operations[j].len);
  249. END
  250. END;
  251. IF p < 0 THEN p := 0 END;
  252. positions[i] := p
  253. END
  254. END;
  255. nofOperations := 0
  256. END Cleanup;
  257. (** Listens for text changes *)
  258. PROCEDURE Changed*(op, pos, len : LONGINT);
  259. CONST MaxOperations = 4096;
  260. BEGIN
  261. IF nofOperations > MaxOperations THEN Cleanup END;
  262. IF nofOperations >= LEN(operations) THEN GrowOperations END;
  263. operations[nofOperations].op := op;
  264. operations[nofOperations].pos := pos;
  265. operations[nofOperations].len := len;
  266. INC(nofOperations)
  267. END Changed;
  268. PROCEDURE GrowPositions;
  269. VAR i : LONGINT;
  270. t : LongintArray;
  271. BEGIN
  272. NEW(t, nofPositions * 2);
  273. FOR i := 0 TO nofPositions - 1 DO t[i] := positions[i] END;
  274. positions := t
  275. END GrowPositions;
  276. PROCEDURE DeletePos*(index : LONGINT);
  277. BEGIN
  278. positions[index] := -1;
  279. INC(nofDeleted)
  280. END DeletePos;
  281. PROCEDURE AddPos*(pos : LONGINT) : LONGINT;
  282. VAR i : LONGINT;
  283. BEGIN
  284. ASSERT(pos >= 0);
  285. Cleanup;
  286. IF nofDeleted > 0 THEN
  287. i := 0; WHILE (i < nofPositions) & (positions[i] >= 0) DO INC(i) END;
  288. ASSERT(i < nofPositions);
  289. positions[i] := pos;
  290. DEC(nofDeleted);
  291. RETURN i
  292. ELSE
  293. IF nofPositions >= LEN(positions) THEN GrowPositions END;
  294. positions[nofPositions] := pos;
  295. INC(nofPositions);
  296. RETURN nofPositions - 1
  297. END
  298. END AddPos;
  299. (** throw away all positions *)
  300. PROCEDURE Clear*;
  301. BEGIN
  302. nofPositions := 0; nofOperations := 0
  303. END Clear;
  304. (** Returns position in elements from the text start *)
  305. PROCEDURE GetPos*(index : LONGINT):LONGINT;
  306. BEGIN
  307. Cleanup;
  308. RETURN positions[index]
  309. END GetPos;
  310. (** Change the position associated with index*)
  311. PROCEDURE SetPos*(index, pos : LONGINT);
  312. BEGIN
  313. Cleanup;
  314. positions[index] := pos
  315. END SetPos;
  316. END TextPositionKeeper;
  317. OberonDecoder = OBJECT(Codecs.TextDecoder)
  318. VAR errors : BOOLEAN;
  319. in : Streams.Reader;
  320. text : Texts.Text;
  321. buffer : Strings.Buffer;
  322. string: Strings.String;
  323. reader, sreader : Streams.StringReader;
  324. PROCEDURE Error(CONST x : ARRAY OF CHAR);
  325. BEGIN
  326. KernelLog.String("Oberon Decoder Error: ");
  327. KernelLog.String(x); KernelLog.Ln;
  328. errors := TRUE
  329. END Error;
  330. PROCEDURE LoadLibrary(buf: Strings.Buffer; pos:LONGINT; VARflen:LONGINT);
  331. END LoadLibrary;
  332. PROCEDURE IndexToColor(index: LONGINT): LONGINT;
  333. BEGIN
  334. RETURN
  335. ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {5..7}), 23-7) +
  336. ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {2..4}), 15-4) +
  337. ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {0..1}), 7-1)
  338. END IndexToColor;
  339. PROCEDURE InsertPiece(ofs, len : LONGINT; attr : Texts.Attributes);
  340. VAR i, j, m : LONGINT; ch, last : CHAR; tempUCS32 : ARRAY 1024 OF Char32;
  341. oldpos : LONGINT;
  342. BEGIN
  343. m := LEN(tempUCS32) - 1;
  344. sreader.SetPos(ofs);
  345. oldpos := text.GetLength();
  346. FOR j := 0 TO len - 1 DO
  347. ch := sreader.Get();
  348. IF i = m THEN tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32); i := 0 END;
  349. IF (last # CR) OR (ch # LF) THEN
  350. IF ch = CR THEN tempUCS32[i] := ORD(LF)
  351. ELSE tempUCS32[i] := OberonToUni(ORD(ch))
  352. END;
  353. INC(i)
  354. END;
  355. last := ch
  356. END;
  357. tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32);
  358. IF attr # NIL THEN text.SetAttributes(oldpos, len, attr) END
  359. END InsertPiece;
  360. PROCEDURE Open*(in : Streams.Reader; VAR res : WORD);
  361. CONST DocBlockId = 0F7X; OldTextBlockId = 1X; TextBlockId = 0F0X; OldTextSpex = 0F0X; TextSpex = 1X; LibBlockId = 0DBX;
  362. VAR
  363. ch: CHAR;
  364. tempInt : LONGINT;
  365. buflen: LONGINT;
  366. attr : Texts.Attributes;
  367. tattr : Texts.FontInfo;
  368. fonts : ARRAY 256 OF Texts.FontInfo;
  369. col: SHORTINT;
  370. voff: SHORTINT;
  371. lib :SHORTINT;
  372. type, tag: CHAR;
  373. len, flen, n, off, hlen, tlen, pos, templen: LONGINT;
  374. x, y, w, h: INTEGER;
  375. temp: ARRAY 4096 OF CHAR;
  376. name, lName: ARRAY 32 OF CHAR;
  377. oberonColors : ARRAY 16 OF LONGINT;
  378. BEGIN
  379. errors := FALSE;
  380. res := -1;
  381. IF in = NIL THEN Error("Input Stream is NIL"); RETURN; END;
  382. SELF.in := in;
  383. (* write stream into buffer for further processing *)
  384. NEW(buffer, 64 * 1024);
  385. REPEAT
  386. in.Bytes(temp, 0, 4096, buflen);
  387. buffer.Add(temp, 0, buflen, FALSE, res);
  388. UNTIL (in.res # Streams.Ok);
  389. (* define Oberon Colors *)
  390. oberonColors[0] := LONGINT(0FFFFFFFFH); oberonColors[1] := LONGINT(0FF0000FFH); oberonColors[2] := 000FF00FFH; oberonColors[3] := 00000FFFFH;
  391. oberonColors[4] := LONGINT(0FF00FFFFH); oberonColors[5] := LONGINT(0FFFF00FFH); oberonColors[6] := 000FFFFFFH; oberonColors[7] := LONGINT(0AA0000FFH);
  392. oberonColors[8] := 000AA00FFH; oberonColors[9] := 00000AAFFH; oberonColors[10] := LONGINT(0A6BCF3FFH); oberonColors[11] := 0008282FFH;
  393. oberonColors[12] := LONGINT(08A8A8AFFH); oberonColors[13] := LONGINT(0BEBEBEFFH); oberonColors[14] := 07B7B7BFFH; oberonColors[15] := 0000000FFH;
  394. NEW(text);
  395. text.AcquireWrite;
  396. string := buffer.GetString();
  397. NEW(reader, buffer.GetLength());
  398. reader.SetRaw(string^, 0, buffer.GetLength());
  399. ch := reader.Get();
  400. IF ch = DocBlockId THEN (* skip doc header *)
  401. reader.RawString(name); reader.RawInt(x); reader.RawInt(y); reader.RawInt(w); reader.RawInt(h);
  402. ch := reader.Get();
  403. IF ch = 0F7X THEN (* skip meta info *)
  404. ch := reader.Get(); IF ch = 08X THEN reader.RawLInt(len); reader.Bytes(temp, 0, len, templen); ch := reader.Get(); END;
  405. END
  406. END;
  407. pos := reader.Pos();
  408. IF (ch = TextBlockId) OR (ch = OldTextBlockId) THEN
  409. type := reader.Get();
  410. reader.RawLInt(hlen);
  411. NEW(sreader, buffer.GetLength());
  412. tempInt := pos - 1 + hlen - 4;
  413. sreader.SetRaw(string^, 0, buffer.GetLength());
  414. sreader.SetPos(tempInt);
  415. sreader.RawLInt(tlen);
  416. IF (type = TextSpex) OR (type = OldTextSpex) THEN (*T.obs := NIL; flen := 0 *)
  417. ELSE (* NEW(T.obs); Objects.OpenLibrary(T.obs); *)
  418. tempInt := pos - 1 + hlen + tlen;
  419. sreader.SetPos(tempInt);
  420. tag := sreader.Get();
  421. IF tag = LibBlockId THEN LoadLibrary(buffer, pos - 1 + hlen + tlen + 1, flen) END;
  422. INC(flen)
  423. END;
  424. n := 1;
  425. off := pos - 1 + hlen;
  426. WHILE reader.Pos() < pos - 1 + hlen - 5 DO
  427. reader.RawSInt(lib);
  428. IF lib = n THEN
  429. reader.RawString(lName);
  430. NEW(fonts[n]);
  431. COPY(lName, fonts[n].name);
  432. DecodeOberonFontName(lName, fonts[n].name, fonts[n].size, fonts[n].style);
  433. tattr := fonts[n];
  434. INC(n)
  435. ELSE
  436. IF (lib >= 0) & (lib < 255) & (fonts[lib] # NIL) THEN
  437. tattr := fonts[lib];
  438. END
  439. END;
  440. reader.RawSInt(col);
  441. reader.RawSInt(voff); voff := - voff;
  442. reader.RawLInt(len);
  443. IF len < 0 THEN KernelLog.Enter; KernelLog.String(" LoadAscii (T, f);"); KernelLog.Int(len, 0); KernelLog.Exit; RETURN END;
  444. NEW(attr);
  445. CASE col OF
  446. 0..15 : attr.color := oberonColors[col]
  447. ELSE attr.color := IndexToColor(col) * 100H + 0FFH
  448. END;
  449. attr.voff := voff;
  450. NEW(attr.fontInfo);
  451. IF tattr # NIL THEN
  452. COPY(tattr.name, attr.fontInfo.name);
  453. attr.fontInfo.style := tattr.style;
  454. attr.fontInfo.size := tattr.size
  455. END;
  456. IF lib > 0 THEN (* ignore objects for now *)
  457. InsertPiece(off, len, attr)
  458. END;
  459. off := off + len
  460. END;
  461. res := 0;
  462. ELSE Error("Not an Oberon File Format!");
  463. END;
  464. text.ReleaseWrite;
  465. END Open;
  466. PROCEDURE GetText*() : Texts.Text;
  467. BEGIN
  468. RETURN text;
  469. END GetText;
  470. (* map oberon to unicode *)
  471. PROCEDURE OberonToUni(ch : LONGINT) : LONGINT;
  472. VAR ret : LONGINT;
  473. BEGIN
  474. CASE ch OF
  475. 128 : ret := 0C4H;
  476. | 129 : ret:= 0D6H;
  477. | 130 : ret:= 0DCH;
  478. | 131 : ret:= 0E4H;
  479. | 132 : ret:= 0F6H;
  480. | 133 : ret:= 0FCH;
  481. | 134 : ret:= 0E2H;
  482. | 135 : ret:= 0EAH;
  483. | 136 : ret:= 0EEH;
  484. | 137 : ret:= 0F4H;
  485. | 138 : ret:= 0FBH;
  486. | 139 : ret:= 0E0H;
  487. | 140 : ret:= 0E8H;
  488. | 141 : ret:= 0ECH;
  489. | 142 : ret:= 0F2H;
  490. | 143 : ret:= 0F9H;
  491. | 144 : ret:= 0E9H;
  492. | 145 : ret:= 0EBH;
  493. | 146 : ret:= 0EFH;
  494. | 147 : ret:= 0E7H;
  495. | 148 : ret:= 0E1H;
  496. | 149 : ret:= 0F1H;
  497. | 150 : ret:= 0DFH;
  498. | 151 : ret:= 0A3H;
  499. | 152 : ret:= 0B6H;
  500. | 153 : ret:= 0C7H;
  501. | 154 : ret:= 2030H;
  502. | 155 : ret:= 2013H;
  503. ELSE
  504. ret := ch
  505. END;
  506. RETURN ret
  507. END OberonToUni;
  508. END OberonDecoder;
  509. OberonEncoder = OBJECT(Codecs.TextEncoder)
  510. VAR out, w: Streams.Writer;
  511. w2: Streams.StringWriter;
  512. string: Strings.String;
  513. buffer : Strings.Buffer;
  514. oberonColors : ARRAY 16 OF LONGINT;
  515. fonts : ARRAY 256 OF Texts.FontInfo;
  516. font : Texts.FontInfo;
  517. nofFonts, hLen : LONGINT;
  518. firstPiece : BOOLEAN;
  519. voff: LONGINT;
  520. color : LONGINT;
  521. PROCEDURE Open*(out : Streams.Writer);
  522. BEGIN
  523. IF out = NIL THEN KernelLog.String("Oberon Encoder Error: output stream is NIL");
  524. ELSE SELF.out := out;
  525. END;
  526. END Open;
  527. PROCEDURE ColorToIndex(col: LONGINT): LONGINT;
  528. BEGIN
  529. RETURN SYSTEM.VAL(LONGINT,
  530. SYSTEM.VAL(SET, ASH(col, 7-23)) * {5..7} +
  531. SYSTEM.VAL(SET, ASH(col, 4-15)) * {2..4} +
  532. SYSTEM.VAL(SET, ASH(col, 1-7)) * {0..1})
  533. END ColorToIndex;
  534. PROCEDURE GetOberonColor(color : LONGINT):LONGINT;
  535. VAR i: LONGINT;
  536. BEGIN
  537. i := 0; WHILE i < LEN(oberonColors) DO IF oberonColors[i] = color THEN RETURN i END; INC(i) END;
  538. RETURN ColorToIndex(color DIV 100H)
  539. END GetOberonColor;
  540. PROCEDURE WritePiece(len: LONGINT);
  541. VAR i :LONGINT; oname : ARRAY 32 OF CHAR;
  542. BEGIN
  543. IF (font # NIL) THEN
  544. i := 0; WHILE (i < nofFonts) & (~fonts[i].IsEqual(font)) DO INC(i) END;
  545. IF (i = nofFonts) THEN
  546. IF ToOberonFont(font.name, font.size, font.style, oname) THEN
  547. w.RawSInt(SHORT(SHORT(i+1)));
  548. IF i = nofFonts THEN w.RawString(oname); fonts[nofFonts] := font; INC(nofFonts) END
  549. ELSE
  550. w.RawSInt(1);
  551. IF firstPiece THEN
  552. w.RawString("Oberon10.Scn.Fnt");
  553. NEW(fonts[nofFonts]);
  554. fonts[nofFonts].name := "Oberon"; fonts[nofFonts].size := 10; fonts[nofFonts].style := {};
  555. INC(nofFonts)
  556. END;
  557. END
  558. ELSE w.RawSInt(SHORT(SHORT(i+1)));
  559. END
  560. ELSE
  561. w.RawSInt(1);
  562. IF firstPiece THEN
  563. w.RawString("Oberon10.Scn.Fnt");
  564. NEW(fonts[nofFonts]);
  565. fonts[nofFonts].name := "Oberon"; fonts[nofFonts].size := 10; fonts[nofFonts].style := {};
  566. INC(nofFonts)
  567. END;
  568. END;
  569. firstPiece := FALSE;
  570. w.RawSInt(SHORT(SHORT(GetOberonColor(color))));
  571. w.RawSInt(SHORT(SHORT(-voff)));
  572. w.RawLInt(len);
  573. END WritePiece;
  574. PROCEDURE WriteText*(text : Texts.Text; VAR res : WORD);
  575. CONST TextBlockId = 0F0X;
  576. VAR r: Texts.TextReader;
  577. ch :Char32;
  578. startPos, i, len, tempInt : LONGINT;
  579. BEGIN
  580. (* define Oberon colors *)
  581. oberonColors[0] := LONGINT(0FFFFFFFFH); oberonColors[1] := LONGINT(0FF0000FFH); oberonColors[2] := 000FF00FFH; oberonColors[3] := 00000FFFFH;
  582. oberonColors[4] := LONGINT(0FF00FFFFH); oberonColors[5] := LONGINT(0FFFF00FFH); oberonColors[6] := 000FFFFFFH; oberonColors[7] := LONGINT(0AA0000FFH);
  583. oberonColors[8] := 000AA00FFH; oberonColors[9] := 00000AAFFH; oberonColors[10] := LONGINT(0A6BCF3FFH); oberonColors[11] := 0008282FFH;
  584. oberonColors[12] := LONGINT(08A8A8AFFH); oberonColors[13] := LONGINT(0BEBEBEFFH); oberonColors[14] := 07B7B7BFFH; oberonColors[15] := 0000000FFH;
  585. res := -1;
  586. text.AcquireRead;
  587. firstPiece := TRUE;
  588. NEW(r, text);
  589. NEW(buffer, 1024);
  590. w := buffer.GetWriter();
  591. nofFonts := 0;
  592. w.Char(TextBlockId);
  593. w.Char(01X); (* simple text *)
  594. w.RawLInt(0); (* header len place holder *)
  595. startPos := 1; len := 0;
  596. REPEAT
  597. r.ReadCh(ch);
  598. IF ~r.eot & (ch >= 0) & (ch < 256) THEN
  599. INC(len);
  600. IF len < 2 THEN font := r.font; voff := r.voff; color := r.color END;
  601. IF (r.font # font) OR (r.voff # voff) OR (r.color # color) THEN
  602. WritePiece(len - startPos);
  603. font := r.font; voff := r.voff; color := r.color;
  604. startPos := len;
  605. END
  606. END
  607. UNTIL r.eot;
  608. WritePiece(len + 1 - startPos);
  609. w.Char(0X); (* ??? *)
  610. w.RawLInt(len); (* tLen ? *)
  611. w.Update;
  612. hLen := w.Pos();
  613. (* pure text ... *)
  614. r.SetPosition(0);
  615. FOR i := 0 TO text.GetLength() - 1 DO r.ReadCh(ch); IF ch = Texts.NewLineChar THEN ch := 0DH END;
  616. IF (ch >=0) & (ch < 256) THEN w.Char(CHR(UniToOberon(ch))) END
  617. END;
  618. (* fixup header length *)
  619. w.Update;
  620. string := buffer.GetString();
  621. NEW(w2, LEN(string));
  622. w2.Bytes(string^, 0, LEN(string));
  623. tempInt := w2.Pos();
  624. w2.SetPos(2);
  625. w2.RawLInt(hLen);
  626. w2.SetPos(tempInt); w2.Update;
  627. (* write string to output stream *)
  628. NEW(string, text.GetLength()+hLen);
  629. w2.GetRaw(string^, len);
  630. out.Bytes(string^, 0, len); out.Update;
  631. text.ReleaseRead;
  632. res := 0
  633. END WriteText;
  634. (* map unicode to oberon *)
  635. PROCEDURE UniToOberon(ch : LONGINT) : LONGINT;
  636. VAR ret : LONGINT;
  637. BEGIN
  638. CASE ch OF
  639. 0C4H : ret := 128;
  640. | 0D6H : ret := 129;
  641. | 0DCH : ret := 130;
  642. | 0E4H : ret := 131;
  643. | 0F6H : ret := 132;
  644. | 0FCH : ret := 133;
  645. | 0E2H : ret := 134;
  646. | 0EAH : ret := 135;
  647. | 0EEH : ret := 136;
  648. | 0F4H : ret := 137;
  649. | 0FBH : ret := 138;
  650. | 0E0H : ret := 139;
  651. | 0E8H : ret := 140;
  652. | 0ECH : ret := 141;
  653. | 0F2H : ret := 142;
  654. | 0F9H : ret := 143;
  655. | 0E9H : ret := 144;
  656. | 0EBH : ret := 145;
  657. | 0EFH : ret := 146;
  658. | 0E7H : ret := 147;
  659. | 0E1H : ret := 148;
  660. | 0F1H : ret := 149;
  661. | 0DFH : ret := 150;
  662. | 0A3H : ret := 151;
  663. | 0B6H : ret := 152;
  664. | 0C7H : ret := 153;
  665. ELSE
  666. IF ch = 2030H THEN ret := 154
  667. ELSIF ch = 2013H THEN ret := 155
  668. ELSE ret := ch
  669. END
  670. END;
  671. RETURN ret
  672. END UniToOberon;
  673. END OberonEncoder;
  674. BluebottleDecoder* = OBJECT(Codecs.TextDecoder)
  675. VAR errors : BOOLEAN;
  676. text : Texts.Text;
  677. doc : XML.Document;
  678. cont, tc, tc2 : XMLObjects.Enumerator; ptr : ANY; root : XML.Element; str : Strings.String;
  679. o : Texts.ObjectPiece; attr: Texts.Attributes; fi : Texts.FontInfo;
  680. stylename, pstylename: ARRAY 64 OF CHAR;
  681. link : Texts.Link;
  682. PROCEDURE Error(CONST x : ARRAY OF CHAR);
  683. BEGIN
  684. KernelLog.String("Bluebottle Decoder Error: ");
  685. KernelLog.String(x); KernelLog.Ln;
  686. errors := TRUE
  687. END Error;
  688. PROCEDURE GetUTF8Char(r : Streams.Reader; VAR u : Texts.Char32; VAR pos : LONGINT) : BOOLEAN;
  689. VAR ch : ARRAY 8 OF CHAR; i : LONGINT;
  690. BEGIN
  691. ch[0] := r.Get(); INC(pos);
  692. FOR i := 1 TO ORD(UTF8Strings.CodeLength[ORD(ch[0])]) - 1 DO ch[i] := r.Get(); INC(pos) END;
  693. i := 0;
  694. RETURN UTF8Strings.DecodeChar(ch, i, u)
  695. END GetUTF8Char;
  696. PROCEDURE InsertPiece(charContent : XML.CDataSect);
  697. VAR i, m, tpos: LONGINT; res : WORD; ch, last : Texts.Char32; tempUCS32 : ARRAY 1024 OF Texts.Char32;
  698. oldpos, len : LONGINT;
  699. r, sr : Streams.StringReader; token : ARRAY 256 OF CHAR;
  700. tempInt: LONGINT;
  701. buffer : Strings.String;
  702. char : CHAR;
  703. cStyle : Texts.CharacterStyle;
  704. pStyle : Texts.ParagraphStyle;
  705. BEGIN
  706. m := LEN(tempUCS32) - 1;
  707. buffer := charContent.GetStr();
  708. NEW(r, LEN(buffer^));
  709. r.Set(buffer^);
  710. oldpos := text.GetLength();
  711. len := charContent.GetLength();
  712. tpos := 0;
  713. REPEAT
  714. IF GetUTF8Char(r, ch, tpos) THEN
  715. IF i = m THEN tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32); i := 0 END;
  716. IF (last # ORD(CR)) OR (ch # ORD(LF)) THEN
  717. IF ch = ORD(CR) THEN tempUCS32[i] := ORD(LF)
  718. ELSE tempUCS32[i] := ch
  719. END;
  720. INC(i)
  721. END;
  722. last := ch;
  723. END
  724. UNTIL (tpos >= len) OR (r.res # Streams.Ok);
  725. tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32);
  726. (* get style from the System *)
  727. cStyle := Texts.GetCharacterStyleByName(stylename);
  728. pStyle := Texts.GetParagraphStyleByName(pstylename);
  729. (* set attributes to emulate style in non-style supporting applications *)
  730. IF (attr = NIL) THEN NEW(attr); END;
  731. attr.voff := 0; attr.color := 0000000FFH; attr.bgcolor := 000000000H;
  732. IF (attr.fontInfo = NIL) THEN NEW(fi); attr.fontInfo := fi; END;
  733. attr.fontInfo.name := "Oberon"; attr.fontInfo.size := 10; attr.fontInfo.style := {};
  734. IF (stylename = "Bold") THEN attr.fontInfo.style := {0};
  735. ELSIF (stylename = "Highlight") THEN attr.fontInfo.style := {1};
  736. ELSIF (stylename = "Assertion") THEN attr.fontInfo.style := {0}; attr.color := 00000FFFFH;
  737. ELSIF (stylename = "Debug") THEN attr.color := 00000FFFFH;
  738. ELSIF (stylename = "Lock") THEN attr.color := LONGINT(0FF00FFFFH);
  739. ELSIF (stylename = "Stupid") THEN attr.color := LONGINT(0FF0000FFH);
  740. ELSIF (stylename = "Comment") THEN attr.color := LONGINT(0808080FFH);
  741. ELSIF (stylename = "Preferred") THEN attr.fontInfo.style := {0}; attr.color := LONGINT(0800080FFH);
  742. ELSIF Strings.Match("AdHoc*", stylename) THEN
  743. NEW(sr, LEN(stylename)); sr.Set(stylename);
  744. sr.SkipWhitespace; sr.Token(token); (* AdHoc *)
  745. sr.SkipWhitespace; sr.Token(token); COPY(token, attr.fontInfo.name); (* family *)
  746. sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, attr.fontInfo.size); (* size *)
  747. sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, tempInt); (* style *)
  748. IF (tempInt = 0) THEN attr.fontInfo.style := {};
  749. ELSIF (tempInt = 1) THEN attr.fontInfo.style := {0};
  750. ELSIF (tempInt = 2) THEN attr.fontInfo.style := {1};
  751. ELSIF (tempInt = 3) THEN attr.fontInfo.style := {0,1};
  752. ELSE attr.fontInfo.style := {};
  753. END;
  754. sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, attr.voff); (* voff *)
  755. sr.SkipWhitespace; sr.Token(token); Strings.HexStrToInt(token, attr.color, res); (* color *)
  756. sr.SkipWhitespace; sr.Token(token); Strings.HexStrToInt(token, attr.bgcolor, res); (* bgcolor *)
  757. (* add Ad-Hoc style to the System in case it was not present already *)
  758. IF cStyle = NIL THEN
  759. NEW(cStyle);
  760. COPY(stylename, cStyle.name);
  761. COPY(attr.fontInfo.name, cStyle.family);
  762. cStyle.size := FP1616.FloatToFixp(attr.fontInfo.size);
  763. cStyle.style := attr.fontInfo.style;
  764. cStyle.baselineShift := attr.voff;
  765. cStyle.color := attr.color;
  766. cStyle.bgColor := attr.bgcolor;
  767. Texts.AddCharacterStyle(cStyle);
  768. END;
  769. ELSE
  770. (* Get the attributes from the style for compatibility *)
  771. IF (cStyle # NIL) THEN attr := StyleToAttribute(cStyle)
  772. ELSE token := "Style not present in System: "; Strings.Append(token, stylename); Error(token); END;
  773. END;
  774. text.SetAttributes(oldpos, text.GetLength()-oldpos, attr.Clone());
  775. (* set the style for style supporting applications *)
  776. text.SetCharacterStyle(oldpos, text.GetLength()-oldpos, cStyle);
  777. (* Get AdHoc paragraph style & add to system *)
  778. IF Strings.Match("AdHoc*", pstylename) & (pStyle = NIL) THEN
  779. NEW(pStyle);
  780. NEW(sr, LEN(pstylename)); sr.Set(pstylename);
  781. sr.SkipWhitespace; sr.Token(token); COPY(pstylename, pStyle.name); (* AdHoc *)
  782. sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, tempInt); pStyle.alignment := tempInt; (* alignment *)
  783. sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, tempInt); pStyle.firstIndent := FP1616.FloatToFixp(tempInt); (* first Indent *)
  784. sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, tempInt); pStyle.leftIndent := FP1616.FloatToFixp(tempInt); (* left Indent *)
  785. sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, tempInt); pStyle.rightIndent := FP1616.FloatToFixp(tempInt); (* right Indent *)
  786. sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, tempInt); pStyle.spaceBefore := FP1616.FloatToFixp(tempInt); (* space above *)
  787. sr.SkipWhitespace; sr.Token(token); Strings.StrToInt(token, tempInt); pStyle.spaceAfter := FP1616.FloatToFixp(tempInt); (* space below *)
  788. sr.SkipWhitespace; char := sr.Peek(); IF (char = "t") THEN sr.SkipBytes(1); sr.RawString(token); COPY(token, pStyle.tabStops); END; (* tabstops *)
  789. Texts.AddParagraphStyle(pStyle);
  790. END;
  791. (* set the paragraph style *)
  792. IF (pStyle # NIL) THEN text.SetParagraphStyle(oldpos, text.GetLength()-oldpos, pStyle) END;
  793. (* set the link *)
  794. text.SetLink(oldpos, text.GetLength()-oldpos, link);
  795. END InsertPiece;
  796. PROCEDURE InsertChar(pos : LONGINT; ch : Texts.Char32);
  797. VAR bufUCS32 : ARRAY 2 OF Texts.Char32;
  798. oldpos : LONGINT;
  799. cStyle : Texts.CharacterStyle;
  800. pStyle : Texts.ParagraphStyle;
  801. BEGIN
  802. bufUCS32[0] := ch; bufUCS32[1] := 0;
  803. oldpos := text.GetLength();
  804. text.InsertUCS32(pos, bufUCS32); (* cursor moves automagically *)
  805. (* get style from the System *)
  806. cStyle := Texts.GetCharacterStyleByName(stylename);
  807. pStyle := Texts.GetParagraphStyleByName(pstylename);
  808. (* set the character style *)
  809. IF (cStyle # NIL) THEN text.SetCharacterStyle(oldpos, text.GetLength()-oldpos, cStyle) END;
  810. (* set the paragraph style *)
  811. IF (pStyle # NIL) THEN text.SetParagraphStyle(oldpos, text.GetLength()-oldpos, pStyle) END;
  812. (* set the link *)
  813. IF (link # NIL) THEN text.SetLink(oldpos, text.GetLength()-oldpos, link); KernelLog.String("bonk"); END;
  814. END InsertChar;
  815. PROCEDURE MalformedXML(pos, line, row: LONGINT; CONST msg: ARRAY OF CHAR);
  816. BEGIN
  817. Error(msg);
  818. END MalformedXML;
  819. PROCEDURE Open*(in : Streams.Reader; VAR res : WORD);
  820. VAR
  821. scanner : XMLScanner.Scanner; parser : XMLParser.Parser;
  822. d : XML.Document;
  823. BEGIN
  824. res := -1;
  825. errors := FALSE;
  826. IF in = NIL THEN Error("Input Stream is NIL"); RETURN; END;
  827. NEW(scanner, in); NEW(parser, scanner);
  828. parser.elemReg := Repositories.registry;
  829. parser.reportError := MalformedXML;
  830. d := parser.Parse();
  831. IF errors THEN RETURN END;
  832. OpenXML(d);
  833. res := 0;
  834. END Open;
  835. PROCEDURE OpenXML*(d : XML.Document);
  836. VAR lp : Texts.LabelPiece;
  837. BEGIN
  838. errors := FALSE;
  839. doc := d;
  840. NEW(text);
  841. text.AcquireWrite;
  842. NEW(attr);
  843. root := doc.GetRoot();
  844. cont := root.GetContents(); cont.Reset();
  845. WHILE cont.HasMoreElements() DO
  846. ptr := cont.GetNext();
  847. IF ptr IS XML.Element THEN
  848. str := ptr(XML.Element).GetName();
  849. IF (str # NIL) & (str^ = "Label") THEN
  850. str := ptr(XML.Element).GetAttributeValue("name");
  851. IF str # NIL THEN NEW(lp); lp.label := Strings.NewString(str^); text.InsertPiece(text.GetLength(), lp) END;
  852. ELSIF (str # NIL) & (str^ = "Paragraph") THEN
  853. tc := ptr(XML.Element).GetContents(); tc.Reset();
  854. str := ptr(XML.Element).GetAttributeValue("style");
  855. IF str # NIL THEN COPY(str^, pstylename); END;
  856. WHILE tc.HasMoreElements() DO
  857. ptr := tc.GetNext();
  858. IF ptr IS XML.Element THEN
  859. str := ptr(XML.Element).GetName();
  860. IF (str # NIL) & (str^ = "Label") THEN
  861. str := ptr(XML.Element).GetAttributeValue("name");
  862. IF str # NIL THEN NEW(lp); lp.label := Strings.NewString(str^); text.InsertPiece(text.GetLength(), lp) END;
  863. ELSIF (str # NIL) & (str^ = "Span") THEN
  864. tc2 := ptr(XML.Element).GetContents(); tc2.Reset();
  865. str := ptr(XML.Element).GetAttributeValue("style"); IF str # NIL THEN COPY(str^, stylename); END;
  866. str := ptr(XML.Element).GetAttributeValue("link"); IF str # NIL THEN NEW(link, LEN(str^)); COPY(str^, link^); ELSE link := NIL; END;
  867. WHILE tc2.HasMoreElements() DO
  868. ptr := tc2.GetNext();
  869. IF ptr IS XML.CDataSect THEN InsertPiece(ptr(XML.CDataSect)) END;
  870. END;
  871. ELSIF (str # NIL) & (str^ = "Object") THEN
  872. tc2 := ptr(XML.Element).GetContents(); tc2.Reset();
  873. IF tc2.HasMoreElements() THEN
  874. NEW(o); o.object := tc2.GetNext(); text.InsertPiece(text.GetLength(), o);
  875. END
  876. END
  877. END
  878. END;
  879. (* Insert a newline to finish paragraph *)
  880. (* InsertChar(text.GetLength(), Texts.NewLineChar); *)
  881. ELSIF (str # NIL) & (str^ = "Span") THEN
  882. COPY("Left", pstylename);
  883. tc := ptr(XML.Element).GetContents(); tc.Reset();
  884. str := ptr(XML.Element).GetAttributeValue("style"); IF str # NIL THEN COPY(str^, stylename); END;
  885. str := ptr(XML.Element).GetAttributeValue("link"); IF str # NIL THEN NEW(link, LEN(str^)); COPY(str^, link^); ELSE link := NIL; END;
  886. WHILE tc.HasMoreElements() DO
  887. ptr := tc.GetNext();
  888. IF ptr IS XML.CDataSect THEN InsertPiece(ptr(XML.CDataSect)) END;
  889. END
  890. ELSIF (str # NIL) & (str^ = "Object") THEN
  891. tc := ptr(XML.Element).GetContents(); tc.Reset();
  892. IF tc.HasMoreElements() THEN
  893. NEW(o); o.object := tc.GetNext(); text.InsertPiece(text.GetLength(), o);
  894. END;
  895. END;
  896. END
  897. END;
  898. text.ReleaseWrite;
  899. END OpenXML;
  900. PROCEDURE GetText*() : Texts.Text;
  901. BEGIN
  902. RETURN text;
  903. END GetText;
  904. END BluebottleDecoder;
  905. BluebottleEncoder = OBJECT(Codecs.TextEncoder)
  906. VAR out: Streams.Writer;
  907. ch :Texts.Char32;
  908. r: Texts.TextReader;
  909. changed, pchanged, pOpen : BOOLEAN;
  910. stylename, pstylename: ARRAY 256 OF CHAR;
  911. cStyle: Texts.CharacterStyle;
  912. pStyle: Texts.ParagraphStyle;
  913. link : Texts.Link;
  914. (* hStyle: Texts.HighlightStyle; <-- TO DO
  915. *)
  916. (* Attributes attributes *)
  917. family, dfFamily : ARRAY 64 OF CHAR;
  918. size, dfSize : LONGINT;
  919. style, dfStyle : LONGINT; (* 0 = regular; 1 = bold; 2 = italic; 3 = bold-italic *)
  920. voff, dfVoff : LONGINT;
  921. color, dfColor : LONGINT;
  922. bgcolor, dfBgcolor : LONGINT;
  923. (* Set the default attribute values *)
  924. PROCEDURE Init;
  925. BEGIN
  926. dfFamily := "Oberon";
  927. dfSize := 10;
  928. dfStyle := 0;
  929. dfVoff := 0;
  930. dfColor := 0000000FFH;
  931. dfBgcolor := 000000000H;
  932. END Init;
  933. (* extract the attributes from the current textreader *)
  934. PROCEDURE RetrieveAttributes;
  935. VAR tempstring, string: ARRAY 128 OF CHAR;
  936. BEGIN
  937. (* Get Character Style if any *)
  938. IF (r.cstyle # NIL) THEN
  939. cStyle := r.cstyle;
  940. COPY(cStyle.name, stylename);
  941. COPY(cStyle.family, family);
  942. size := cStyle.size;
  943. IF (cStyle.style = {}) THEN style := 0; ELSIF (cStyle.style = {0}) THEN style := 1; ELSIF (cStyle.style = {1}) THEN style := 2; ELSIF (cStyle.style = {0,1}) THEN style := 3; ELSE style := 0; END;
  944. voff := cStyle.baselineShift;
  945. color := cStyle.color;
  946. bgcolor := cStyle.bgColor;
  947. ELSE
  948. cStyle := NIL;
  949. (* Get attributes from char *)
  950. IF (r.font = NIL) THEN (* Fix missing values *)
  951. family := dfFamily;
  952. size := dfSize;
  953. style := dfStyle;
  954. ELSE
  955. COPY(r.font.name, family);
  956. size := r.font.size;
  957. IF (r.font.style = {}) THEN style := 0; ELSIF (r.font.style = {0}) THEN style := 1; ELSIF (r.font.style = {1}) THEN style := 2; ELSIF (r.font.style = {0,1}) THEN style := 3; ELSE style := 0; END;
  958. END;
  959. voff := r.voff;
  960. color := r.color;
  961. bgcolor := r.bgcolor;
  962. (* Find appropriate style *)
  963. IF (color = 0000000FFH) & (style = 0) THEN stylename := "Normal"
  964. ELSIF (color = 0000000FFH) & (style = 1) THEN stylename := "Bold"
  965. ELSIF (color = 0000000FFH) & (style = 2) THEN stylename := "Highlight"
  966. ELSIF ((color = 00000FFFFH) OR (color = 00000AAFFH)) & (style = 1) THEN stylename := "Assertion"
  967. ELSIF (color = 00000FFFFH) & (style = 0) THEN stylename := "Debug"
  968. ELSIF (color = 0FF00FFFFH) & (style = 0) THEN stylename := "Lock"
  969. ELSIF (color = 0FF0000FFH) & (style = 0) THEN stylename := "Stupid"
  970. ELSIF ((color = 0808080FFH) OR (color = 08A8A8AFFH)) & (style = 0) THEN stylename := "Comment"
  971. ELSIF (color = 0800080FFH) & (style = 1) THEN stylename := "Preferred"
  972. ELSE
  973. tempstring := "AdHoc"; Strings.Append(tempstring, " ");
  974. Strings.Append(tempstring, family); Strings.Append(tempstring, " ");
  975. Strings.IntToStr(size, string); Strings.Append(tempstring, string); Strings.Append(tempstring, " ");
  976. Strings.IntToStr(style, string); Strings.Append(tempstring, string); Strings.Append(tempstring, " ");
  977. Strings.IntToStr(voff, string); Strings.Append(tempstring, string); Strings.Append(tempstring, " ");
  978. Strings.IntToHexStr(color,7, string); Strings.Append(tempstring, string); Strings.Append(tempstring, " ");
  979. Strings.IntToHexStr(bgcolor,7, string); Strings.Append(tempstring, string);
  980. COPY(tempstring, stylename);
  981. (* KernelLog.String("Writing Ad-hoc Style: "); KernelLog.String(tempstring); KernelLog.Ln; *)
  982. END;
  983. END;
  984. (* Get Paragraph Style if any *)
  985. IF (r.pstyle # NIL) THEN
  986. pStyle := r.pstyle;
  987. COPY(pStyle.name, pstylename)
  988. ELSE
  989. pStyle := NIL;
  990. COPY("", pstylename)
  991. END;
  992. (* Get Link if any *)
  993. IF (r.link # NIL) THEN
  994. link := r.link;
  995. ELSE
  996. link := NIL;
  997. END;
  998. END RetrieveAttributes;
  999. PROCEDURE PrintAttributes;
  1000. BEGIN
  1001. KernelLog.String("# family: "); KernelLog.String(family); KernelLog.Ln;
  1002. KernelLog.String("# size: "); KernelLog.Int(size, 0); KernelLog.Ln;
  1003. KernelLog.String("# style: "); KernelLog.Int(style, 0); KernelLog.Ln;
  1004. KernelLog.String("# voff: "); KernelLog.Int(voff, 0); KernelLog.Ln;
  1005. KernelLog.String("# color: "); KernelLog.Hex(color, 0); KernelLog.Ln;
  1006. KernelLog.String("# bgcolor: "); KernelLog.Hex(bgcolor, 0); KernelLog.Ln;
  1007. END PrintAttributes;
  1008. (* Return TRUE if current textreader attributes don't match the chached one *)
  1009. PROCEDURE CompareAttributes():BOOLEAN;
  1010. VAR tempstyle: LONGINT;
  1011. isEqual : BOOLEAN;
  1012. BEGIN
  1013. IF (link = r.link) THEN
  1014. IF r.cstyle # NIL THEN
  1015. isEqual := (stylename = r.cstyle.name);
  1016. RETURN ~isEqual;
  1017. ELSE
  1018. IF (r.font = NIL) THEN
  1019. isEqual := (family = dfFamily) & (size = dfSize) & (style = dfStyle) & (voff = r.voff) & (color = r.color) & (bgcolor = r.bgcolor);
  1020. ELSE
  1021. IF (r.font.style = {}) THEN tempstyle := 0; ELSIF (r.font.style = {0}) THEN tempstyle := 1; ELSIF (r.font.style = {1}) THEN tempstyle := 2; ELSIF (r.font.style = {0,1}) THEN tempstyle := 3; ELSE tempstyle := 0; END;
  1022. isEqual := (family = r.font.name) & (size = r.font.size) & (style = tempstyle) & (voff = r.voff) & (color = r.color) & (bgcolor = r.bgcolor);
  1023. END;
  1024. RETURN ~isEqual;
  1025. END;
  1026. ELSE
  1027. RETURN TRUE;
  1028. END
  1029. END CompareAttributes;
  1030. (* Return TRUE if current textreader paragraphstyle doesn't match the chached one *)
  1031. PROCEDURE CompareParagraphs(): BOOLEAN;
  1032. VAR isEqual : BOOLEAN;
  1033. BEGIN
  1034. IF r.pstyle # NIL THEN
  1035. isEqual := (pstylename = r.pstyle.name);
  1036. RETURN ~isEqual
  1037. ELSIF (r.pstyle = NIL) & (pStyle = NIL) THEN
  1038. RETURN FALSE;
  1039. ELSE
  1040. RETURN TRUE;
  1041. END;
  1042. END CompareParagraphs;
  1043. PROCEDURE WriteParagraph(CONST name : ARRAY OF CHAR);
  1044. BEGIN
  1045. pOpen := TRUE;
  1046. out.String("<Paragraph ");
  1047. out.String('style="'); out.String(name); out.String('"');
  1048. out.String(">")
  1049. END WriteParagraph;
  1050. PROCEDURE CloseParagraph;
  1051. BEGIN
  1052. IF pOpen THEN
  1053. out.String("</Paragraph>");
  1054. pOpen := FALSE;
  1055. END;
  1056. END CloseParagraph;
  1057. PROCEDURE WriteSpan(CONST name: ARRAY OF CHAR);
  1058. BEGIN
  1059. out.String("<Span ");
  1060. out.String('style="'); out.String(name); out.String('"');
  1061. IF link # NIL THEN
  1062. out.String(' link="'); out.String(link^); out.String('"');
  1063. END;
  1064. out.String("><![CDATA[")
  1065. END WriteSpan;
  1066. PROCEDURE CloseSpan;
  1067. BEGIN
  1068. out.String("]]></Span>");
  1069. END CloseSpan;
  1070. PROCEDURE WriteObject(o : ANY);
  1071. BEGIN
  1072. out.Ln;
  1073. out.String("<Object>");
  1074. IF (o # NIL) & (o IS XML.Element) THEN
  1075. o(XML.Element).Write(out, NIL, 1);
  1076. END;
  1077. out.String("</Object>");out.Ln;
  1078. END WriteObject;
  1079. PROCEDURE WriteLabel(CONST label: ARRAY OF CHAR);
  1080. BEGIN
  1081. out.String("<Label ");
  1082. out.String('name="'); out.String(label); out.String('"/>');
  1083. END WriteLabel;
  1084. PROCEDURE Open*(out : Streams.Writer);
  1085. BEGIN
  1086. IF out = NIL THEN KernelLog.String("Bluebottle Encoder Error: output stream is NIL");
  1087. ELSE SELF.out := out;
  1088. END;
  1089. END Open;
  1090. PROCEDURE WriteText*(text : Texts.Text; VAR res : WORD);
  1091. VAR
  1092. buf : Strings.String; rbuf : ARRAY 4 OF CHAR;
  1093. bytesPerChar, length, counter : LONGINT;
  1094. PROCEDURE ExpandBuf(VAR oldBuf: Strings.String; newSize: LONGINT);
  1095. VAR newBuf: Strings.String; i: LONGINT;
  1096. BEGIN
  1097. IF LEN(oldBuf^) >= newSize THEN RETURN END;
  1098. NEW(newBuf, newSize);
  1099. FOR i := 0 TO LEN(oldBuf^)-1 DO
  1100. newBuf[i] := oldBuf[i];
  1101. END;
  1102. oldBuf := newBuf;
  1103. END ExpandBuf;
  1104. BEGIN
  1105. Init;
  1106. res := 1;
  1107. out.String('<?xml version="1.0" encoding="UTF-8"?>'); out.Ln;
  1108. out.String('<?bluebottle format version="0.1" ?>'); out.Ln;
  1109. out.String('<?xml-stylesheet type="text/xsl" href="http://bluebottle.ethz.ch/bluebottle.xsl" ?>'); out.Ln;
  1110. out.String("<Text>"); out.Ln;
  1111. text.AcquireRead;
  1112. NEW(r, text);
  1113. r.ReadCh(ch);
  1114. IF (ch = Texts.LabelChar) THEN WriteLabel(r.object(Texts.LabelPiece).label^) END;
  1115. RetrieveAttributes;
  1116. PrintAttributes;
  1117. IF (pStyle # NIL) & (pstylename # "Left") THEN WriteParagraph(pstylename) END;
  1118. WriteSpan(stylename);
  1119. bytesPerChar := 2;
  1120. length := text.GetLength();
  1121. NEW(buf, length * bytesPerChar); (* UTF8 encoded characters use up to 5 bytes *)
  1122. counter := 0; COPY(" ", rbuf);
  1123. WHILE ~r.eot DO
  1124. WHILE ~UTF8Strings.EncodeChar(ch, buf^, counter) DO
  1125. INC(bytesPerChar);
  1126. ASSERT(bytesPerChar <= 5);
  1127. ExpandBuf(buf, bytesPerChar * length);
  1128. END;
  1129. (* CDATA escape fix *)
  1130. rbuf[0] := rbuf[1]; rbuf[1] := rbuf[2]; rbuf[2] := CHR(ch);
  1131. IF (rbuf = "]]>") THEN
  1132. buf[counter] := 0X;
  1133. out.String(buf^); out.String("]]><![CDATA["); counter := 0;
  1134. buf[counter] := CHR(ch);
  1135. END;
  1136. r.ReadCh(ch);
  1137. IF ch = Texts.ObjectChar THEN
  1138. buf[counter] := 0X; out.String(buf^); counter := 0; COPY(" ", rbuf);
  1139. CloseSpan;
  1140. WriteObject(r.object);
  1141. RetrieveAttributes;
  1142. IF ~r.eot THEN WriteSpan(stylename) END
  1143. ELSIF ch = Texts.LabelChar THEN
  1144. buf[counter] := 0X; out.String(buf^); counter := 0; COPY(" ", rbuf);
  1145. CloseSpan;
  1146. WriteLabel(r.object(Texts.LabelPiece).label^);
  1147. RetrieveAttributes;
  1148. IF ~r.eot THEN WriteSpan(stylename) END
  1149. ELSE
  1150. pchanged := CompareParagraphs();
  1151. changed := CompareAttributes();
  1152. IF pchanged THEN
  1153. RetrieveAttributes;
  1154. IF ~r.eot THEN
  1155. buf[counter] := 0X; out.String(buf^); counter := 0; COPY(" ", rbuf);
  1156. CloseSpan;
  1157. CloseParagraph;
  1158. IF (pStyle # NIL) & (pstylename # "Left") THEN WriteParagraph(pstylename) END;
  1159. WriteSpan(stylename)
  1160. END
  1161. ELSIF changed THEN
  1162. RetrieveAttributes;
  1163. IF ~r.eot THEN
  1164. buf[counter] := 0X; out.String(buf^); counter := 0; COPY(" ", rbuf);
  1165. CloseSpan; WriteSpan(stylename)
  1166. END
  1167. END
  1168. END
  1169. END;
  1170. buf[counter] := 0X;
  1171. out.String(buf^);
  1172. CloseSpan; out.Ln;
  1173. CloseParagraph; out.Ln;
  1174. out.String("</Text>"); out.Ln;
  1175. out.Update;
  1176. text.ReleaseRead;
  1177. res := 0
  1178. END WriteText;
  1179. END BluebottleEncoder;
  1180. UTF8Decoder = OBJECT(Codecs.TextDecoder)
  1181. VAR errors : BOOLEAN;
  1182. in : Streams.Reader;
  1183. text : Texts.Text;
  1184. PROCEDURE Error(CONST x : ARRAY OF CHAR);
  1185. BEGIN
  1186. KernelLog.String("UTF-8 Decoder Error: ");
  1187. KernelLog.String(x); KernelLog.Ln;
  1188. errors := TRUE
  1189. END Error;
  1190. PROCEDURE Open*(in : Streams.Reader; VAR res : WORD);
  1191. VAR i, m: LONGINT;
  1192. tempUCS32 : ARRAY 1024 OF Char32;
  1193. ch, last : Texts.Char32;
  1194. BEGIN
  1195. errors := FALSE;
  1196. res := -1;
  1197. IF in = NIL THEN Error("Input Stream is NIL"); RETURN; END;
  1198. SELF.in := in;
  1199. NEW(text);
  1200. text.AcquireWrite;
  1201. m := LEN(tempUCS32) - 1;
  1202. i := 0;
  1203. REPEAT
  1204. IF GetUTF8Char(in, ch) THEN
  1205. IF i = m THEN tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32); i := 0 END;
  1206. IF (last # ORD(CR)) OR (ch # ORD(LF)) THEN
  1207. IF ch = ORD(CR) THEN tempUCS32[i] := ORD(LF)
  1208. ELSE tempUCS32[i] := ch
  1209. END;
  1210. INC(i)
  1211. END;
  1212. last := ch
  1213. END
  1214. UNTIL (in.res # Streams.Ok);
  1215. tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32);
  1216. (* Set this text explicitly to UTF, which allows it to be reformatted by the bidi formatter *)
  1217. text.SetUTF(TRUE);
  1218. res := 0;
  1219. text.ReleaseWrite
  1220. END Open;
  1221. PROCEDURE GetText*() : Texts.Text;
  1222. BEGIN
  1223. RETURN text;
  1224. END GetText;
  1225. END UTF8Decoder;
  1226. UTF8Encoder = OBJECT(Codecs.TextEncoder)
  1227. VAR out: Streams.Writer;
  1228. PROCEDURE Open*(out : Streams.Writer);
  1229. BEGIN
  1230. IF out = NIL THEN KernelLog.String("UTF-8 Encoder Error: output stream is NIL");
  1231. ELSE SELF.out := out;
  1232. END;
  1233. END Open;
  1234. PROCEDURE WriteText*(text : Texts.Text; VAR res : WORD);
  1235. VAR r : Texts.TextReader; ch : Texts.Char32; i, p : LONGINT; resstr : ARRAY 7 OF CHAR;
  1236. BEGIN
  1237. res := -1;
  1238. text.AcquireRead;
  1239. NEW(r, text);
  1240. FOR i := 0 TO text.GetLength() - 1 DO
  1241. r.ReadCh(ch); p := 0;
  1242. IF (ch > 0) & UTF8Strings.EncodeChar(ch, resstr, p) THEN out.String(resstr) END
  1243. END;
  1244. out.Update;
  1245. text.ReleaseRead;
  1246. res := 0;
  1247. END WriteText;
  1248. END UTF8Encoder;
  1249. ISO88591Decoder = OBJECT(Codecs.TextDecoder)
  1250. VAR errors : BOOLEAN;
  1251. in : Streams.Reader;
  1252. text : Texts.Text;
  1253. PROCEDURE Error(CONST x : ARRAY OF CHAR);
  1254. BEGIN
  1255. KernelLog.String("ISO8859-1 Decoder Error: ");
  1256. KernelLog.String(x); KernelLog.Ln;
  1257. errors := TRUE
  1258. END Error;
  1259. PROCEDURE Open*(in : Streams.Reader; VAR res : WORD);
  1260. VAR i, m: LONGINT;
  1261. tempUCS32 : ARRAY 1024 OF Char32;
  1262. ch, last : CHAR;
  1263. BEGIN
  1264. errors := FALSE;
  1265. res := -1;
  1266. IF in = NIL THEN Error("Input Stream is NIL"); RETURN; END;
  1267. SELF.in := in;
  1268. NEW(text);
  1269. text.AcquireWrite;
  1270. m := LEN(tempUCS32) - 1;
  1271. i := 0;
  1272. REPEAT
  1273. in.Char(ch);
  1274. IF i = m THEN tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32); i := 0 END;
  1275. IF (last # CR) OR (ch # LF) THEN
  1276. IF ch = CR THEN tempUCS32[i] := ORD(LF)
  1277. ELSE tempUCS32[i] := ORD(ch)
  1278. END;
  1279. INC(i)
  1280. END;
  1281. last := ch
  1282. UNTIL (in.res # Streams.Ok);
  1283. tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32);
  1284. res := 0;
  1285. text.ReleaseWrite
  1286. END Open;
  1287. PROCEDURE GetText*() : Texts.Text;
  1288. BEGIN
  1289. RETURN text;
  1290. END GetText;
  1291. END ISO88591Decoder;
  1292. ISO88591Encoder = OBJECT(Codecs.TextEncoder)
  1293. VAR out: Streams.Writer;
  1294. PROCEDURE Open*(out : Streams.Writer);
  1295. BEGIN
  1296. IF out = NIL THEN KernelLog.String("ISO8859-1 Encoder Error: output stream is NIL");
  1297. ELSE SELF.out := out;
  1298. END;
  1299. END Open;
  1300. PROCEDURE WriteText*(text : Texts.Text; VAR res : WORD);
  1301. VAR r : Texts.TextReader; ch : Texts.Char32; i : LONGINT;
  1302. BEGIN
  1303. res := -1;
  1304. text.AcquireRead;
  1305. NEW(r, text);
  1306. FOR i := 0 TO text.GetLength() - 1 DO
  1307. r.ReadCh(ch);
  1308. IF (ch >= 0) & (ch < 256) THEN out.Char(CHR(ch)) END
  1309. END;
  1310. out.Update;
  1311. text.ReleaseRead;
  1312. res := 0;
  1313. END WriteText;
  1314. END ISO88591Encoder;
  1315. HEXDecoder = OBJECT(Codecs.TextDecoder)
  1316. VAR errors : BOOLEAN;
  1317. in : Streams.Reader;
  1318. text : Texts.Text;
  1319. PROCEDURE Error(CONST x : ARRAY OF CHAR);
  1320. BEGIN
  1321. KernelLog.String("HEX Decoder Error: ");
  1322. KernelLog.String(x); KernelLog.Ln;
  1323. errors := TRUE
  1324. END Error;
  1325. PROCEDURE Open*(in : Streams.Reader; VAR res : WORD);
  1326. VAR i, j, m : LONGINT;
  1327. tempUCS32 : ARRAY 1057 OF Char32; (* 1025 *)
  1328. ch : CHAR;
  1329. byte : ARRAY 3 OF CHAR;
  1330. attr: Texts.Attributes; fi : Texts.FontInfo;
  1331. BEGIN
  1332. errors := FALSE;
  1333. res := -1;
  1334. IF in = NIL THEN Error("Input Stream is NIL"); RETURN; END;
  1335. SELF.in := in;
  1336. NEW(text); NEW(attr); NEW(fi);
  1337. fi.name := "Courier";
  1338. fi.size := 10;
  1339. fi.style := {};
  1340. attr.voff := 0;
  1341. attr.color := 0000000FFH;
  1342. attr.bgcolor := 000000000H;
  1343. attr.fontInfo := fi;
  1344. text.AcquireWrite;
  1345. m := LEN(tempUCS32) - 1;
  1346. i := 0; j := 0;
  1347. REPEAT
  1348. in.Char(ch);
  1349. IF (i = m) THEN tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32); i := 0 END;
  1350. Strings.IntToHexStr(ORD(ch), 1, byte);
  1351. tempUCS32[i] := ORD(byte[0]); INC(i);
  1352. tempUCS32[i] := ORD(byte[1]); INC(i);
  1353. tempUCS32[i] := ORD(TAB); INC(i); (* formatting space *)
  1354. INC(j);
  1355. IF (j = 16) THEN j := 0; tempUCS32[i-1] := ORD(LF); END;
  1356. UNTIL (in.res # Streams.Ok);
  1357. tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32);
  1358. res := 0;
  1359. text.SetAttributes(0, text.GetLength(), attr.Clone());
  1360. text.ReleaseWrite
  1361. END Open;
  1362. PROCEDURE GetText*() : Texts.Text;
  1363. BEGIN
  1364. RETURN text;
  1365. END GetText;
  1366. END HEXDecoder;
  1367. HEXEncoder = OBJECT(Codecs.TextEncoder)
  1368. VAR out: Streams.Writer;
  1369. PROCEDURE Open*(out : Streams.Writer);
  1370. BEGIN
  1371. IF out = NIL THEN KernelLog.String("HEX Encoder Error: output stream is NIL");
  1372. ELSE SELF.out := out;
  1373. END;
  1374. END Open;
  1375. PROCEDURE WriteText*(text : Texts.Text; VAR res : WORD);
  1376. VAR r : Texts.TextReader; ch : Texts.Char32; i, j: LONGINT; k : WORD;
  1377. byte : ARRAY 2 OF CHAR;
  1378. BEGIN
  1379. res := -1;
  1380. text.AcquireRead;
  1381. NEW(r, text);
  1382. i := 0;
  1383. FOR i := 0 TO text.GetLength() - 1 DO
  1384. r.ReadCh(ch);
  1385. IF ((ch >= 48) & (ch <= 57)) OR ((ch >= 65) & (ch <= 70)) OR ((ch >= 97) & (ch <= 102)) THEN
  1386. byte[j] := CHR(ch); INC(j);
  1387. END;
  1388. IF (j = 2) THEN j := 0; Strings.HexStrToInt(byte, ch, k); out.Char(CHR(ch)); END;
  1389. END;
  1390. out.Update;
  1391. text.ReleaseRead;
  1392. res := 0;
  1393. END WriteText;
  1394. END HEXEncoder;
  1395. VAR
  1396. unicodePropertyReader : UnicodeProperties.UnicodeTxtReader;
  1397. oberonFontAllocatable*: PROCEDURE( CONST name: ARRAY OF CHAR ): BOOLEAN;
  1398. (* ----------------------------------------------------------------------------------- *)
  1399. (* Return true if the unicode character x should be regarded as a white-space *)
  1400. PROCEDURE IsWhiteSpace*(x : Char32; utf : BOOLEAN) : BOOLEAN;
  1401. BEGIN
  1402. (* lazy initialization of the Unicode Property Reader *)
  1403. IF utf & (unicodePropertyReader = NIL) THEN
  1404. NEW(unicodePropertyReader);
  1405. END;
  1406. (* distinguish between utf-whitespaces and ascii-whitespaces *)
  1407. IF utf THEN
  1408. RETURN (x <= 32) OR
  1409. ((unicodePropertyReader # NIL) & unicodePropertyReader.IsWhiteSpaceChar(x)) OR
  1410. (x = 0A0H) OR (x = 200BH);
  1411. ELSE
  1412. RETURN (x <= 32);
  1413. END;
  1414. END IsWhiteSpace;
  1415. (* Return true if the unicode character x is alpha numeric *)
  1416. PROCEDURE IsAlphaNum*(x:Char32): BOOLEAN;
  1417. BEGIN
  1418. RETURN (ORD("0") <= x) & (x <= ORD("9"))
  1419. OR (ORD("A") <= x) & (x <= ORD("Z") )
  1420. OR (ORD("a") <= x) & (x <= ORD("z") )
  1421. END IsAlphaNum;
  1422. (** Find the position of the next word start to the left *)
  1423. PROCEDURE FindPosWordLeft*(utilreader: Texts.TextReader; pos : LONGINT) : LONGINT;
  1424. VAR ch : Texts.Char32;
  1425. new : LONGINT;
  1426. BEGIN
  1427. utilreader.SetPosition(pos); utilreader.SetDirection(-1);
  1428. utilreader.ReadCh(ch);
  1429. (* special treatment for utf-formatted texts *)
  1430. IF ~utilreader.text.isUTF THEN
  1431. WHILE (IsWhiteSpace(ch,FALSE) & (ch # Texts.NewLineChar)) & (~utilreader.eot) DO
  1432. utilreader.ReadCh(ch)
  1433. END;
  1434. WHILE (IsAlphaNum(ch)) & (~utilreader.eot) DO
  1435. utilreader.ReadCh(ch);
  1436. END;
  1437. ELSE
  1438. WHILE IsWhiteSpace(ch,TRUE) & (ch # Texts.NewLineChar) & ~utilreader.eot DO
  1439. utilreader.ReadCh(ch);
  1440. END;
  1441. WHILE ~IsWhiteSpace(ch,TRUE) & ~utilreader.eot DO
  1442. utilreader.ReadCh(ch);
  1443. END
  1444. END;
  1445. new := utilreader.GetPosition() + 1;
  1446. IF utilreader.eot THEN
  1447. RETURN 0
  1448. ELSIF new = pos THEN
  1449. RETURN new
  1450. ELSE
  1451. RETURN new + 1
  1452. END
  1453. END FindPosWordLeft;
  1454. (** Find the position of the next word start to the right *)
  1455. PROCEDURE FindPosWordRight*(utilreader: Texts.TextReader; pos : LONGINT) : LONGINT;
  1456. VAR ch : Texts.Char32;
  1457. new : LONGINT;
  1458. BEGIN
  1459. utilreader.SetPosition(pos); utilreader.SetDirection(1);
  1460. utilreader.ReadCh(ch);
  1461. (* special treatment for utf-formatted texts *)
  1462. IF ~utilreader.text.isUTF THEN
  1463. WHILE (IsAlphaNum(ch)) & (~utilreader.eot) DO
  1464. utilreader.ReadCh(ch)
  1465. END;
  1466. WHILE (IsWhiteSpace(ch,FALSE) & (ch # Texts.NewLineChar)) & (~utilreader.eot) DO
  1467. utilreader.ReadCh(ch)
  1468. END;
  1469. ELSE
  1470. WHILE ~IsWhiteSpace(ch,TRUE) & ~utilreader.eot DO
  1471. utilreader.ReadCh(ch);
  1472. END;
  1473. WHILE IsWhiteSpace(ch,TRUE) & (ch # Texts.NewLineChar) & ~utilreader.eot DO
  1474. utilreader.ReadCh(ch);
  1475. END;
  1476. END;
  1477. new := utilreader.GetPosition()-1;
  1478. IF utilreader.eot THEN
  1479. RETURN utilreader.text.GetLength()
  1480. ELSIF new = pos THEN
  1481. RETURN new+1
  1482. ELSE
  1483. RETURN new
  1484. END
  1485. END FindPosWordRight;
  1486. (* rearch left until the first NewLineChar is encountered. Return the position of the following character *)
  1487. PROCEDURE FindPosLineStart* (utilreader: Texts.TextReader; pos: LONGINT): LONGINT;
  1488. VAR ch : Texts.Char32;
  1489. BEGIN
  1490. utilreader.SetPosition(pos - 1);
  1491. utilreader.SetDirection(-1);
  1492. utilreader.ReadCh(ch);
  1493. WHILE (ch # Texts.NewLineChar) & (~utilreader.eot) DO utilreader.ReadCh(ch) END;
  1494. IF utilreader.eot THEN RETURN 0
  1495. ELSE RETURN utilreader.GetPosition() + 2
  1496. END
  1497. END FindPosLineStart;
  1498. (** Search right in the text until the first non whitespace is encountered. Return the number of whitespace characters *)
  1499. PROCEDURE CountWhitespace* (utilreader: Texts.TextReader; pos: LONGINT): LONGINT;
  1500. VAR ch : Texts.Char32;
  1501. count : LONGINT;
  1502. BEGIN
  1503. utilreader.SetPosition(pos);
  1504. utilreader.SetDirection(1);
  1505. utilreader.ReadCh(ch);
  1506. count := 0;
  1507. WHILE (IsWhiteSpace(ch,utilreader.text.isUTF)) & (ch # Texts.NewLineChar) & (~utilreader.eot) DO
  1508. INC(count);
  1509. utilreader.ReadCh(ch)
  1510. END;
  1511. RETURN count
  1512. END CountWhitespace;
  1513. (** Procedure to load File without explicit given Format - appropriate Format will be chosen automaticaly *)
  1514. PROCEDURE LoadAuto*(text: Text; CONST fileName: ARRAY OF CHAR; VAR format: LONGINT; VAR res: WORD);
  1515. VAR f : Files.File; re : Files.Reader; ri: Files.Rider; ch: CHAR; fstring: ARRAY 64 OF CHAR; i: LONGINT;
  1516. BEGIN
  1517. (* KernelLog.String("Auto Format.... "); KernelLog.Ln; *)
  1518. text.AcquireWrite;
  1519. res := -1; format := -1;
  1520. f := Files.Old(fileName);
  1521. IF f # NIL THEN
  1522. Files.OpenReader(re, f, 0);
  1523. f.Set(ri, 0);
  1524. f.Read(ri, ch); i := ORD(ch);
  1525. IF (i = 0F0H) OR (i = 0F7H) OR (i = 01H) THEN (* Oberon File Format *)
  1526. format := 0;
  1527. ELSIF (i = 03CH) THEN (* possibly an XML, check further *)
  1528. (* check IF just an XML or BB Format *)
  1529. f.Set(ri, 0);
  1530. Files.ReadString(ri, fstring);
  1531. Strings.UpperCase(fstring);
  1532. IF Strings.Match("<?XML VERSION=*", fstring) THEN
  1533. IF Strings.Match("*<?BLUEBOTTLE FORMAT*", fstring) THEN
  1534. format := 1; (* Bluebottle File Format *)
  1535. ELSE
  1536. format := 2; (* XML - treat as UTF-8 *)
  1537. END;
  1538. ELSE
  1539. format := 2; (* Text/Other - treat as UTF-8 *)
  1540. END;
  1541. ELSE (* Neither Oberon nor XML/BB *)
  1542. format := 2;
  1543. END;
  1544. END;
  1545. text.ReleaseWrite;
  1546. (* call correct loader *)
  1547. CASE format OF
  1548. | 0: LoadOberonText(text, fileName, res);
  1549. | 1: LoadText(text, fileName, res);
  1550. | 2: LoadUTF8(text, fileName, res);
  1551. ELSE
  1552. LoadUTF8(text, fileName, res)
  1553. END
  1554. END LoadAuto;
  1555. (** Procedure to get decoder for the given file - appropriate Format will be chosen automaticaly *)
  1556. PROCEDURE DecodeAuto*( CONST fileName: ARRAY OF CHAR; VAR format: ARRAY OF CHAR): Codecs.TextDecoder;
  1557. VAR reader : Streams.Reader; decoder : Codecs.TextDecoder; fstring : ARRAY 64 OF CHAR; i : LONGINT;
  1558. BEGIN
  1559. reader := Codecs.OpenInputStream(fileName);
  1560. IF (reader # NIL) THEN
  1561. reader.String(fstring);
  1562. i := ORD(fstring[0]);
  1563. IF (i = 0F0H) OR (i = 0F7H) OR (i = 01H) THEN
  1564. COPY("Oberon", format); (* Oberon File Format *)
  1565. ELSIF (i = 03CH) THEN
  1566. (* possibly an XML, check further, check IF just an XML or BB Format *)
  1567. Strings.UpperCase(fstring);
  1568. IF Strings.Match("<?XML VERSION=*", fstring) THEN
  1569. IF Strings.Match("*<?BLUEBOTTLE FORMAT*", fstring) THEN
  1570. COPY("BBT", format); (* Bluebottle File Format *)
  1571. ELSE
  1572. COPY("UTF-8", format); (* XML - treat as UTF-8 *)
  1573. END;
  1574. ELSE
  1575. COPY("UTF-8", format); (* Text/Other - treat as UTF-8 *)
  1576. END;
  1577. ELSE
  1578. COPY("UTF-8", format); (* Neither Oberon nor XML/BB *)
  1579. END;
  1580. ELSE
  1581. COPY("", format); (* Could not open input stream *)
  1582. END;
  1583. decoder := Codecs.GetTextDecoder(format);
  1584. RETURN decoder;
  1585. END DecodeAuto;
  1586. (** Load text using codecs *)
  1587. PROCEDURE Load*(text : Text; CONST filename, format : ARRAY OF CHAR; VAR res : WORD);
  1588. VAR decoder : Codecs.TextDecoder; in: Streams.Reader; t : Text;
  1589. BEGIN
  1590. ASSERT(text # NIL);
  1591. decoder := Codecs.GetTextDecoder(format);
  1592. IF (decoder # NIL) THEN
  1593. in := Codecs.OpenInputStream(filename);
  1594. IF ( in # NIL) THEN
  1595. decoder.Open(in, res);
  1596. IF (res = Ok) THEN
  1597. t := decoder.GetText();
  1598. t.AcquireRead;
  1599. text.AcquireWrite;
  1600. text.CopyFromText(t, 0, t.GetLength(), 0);
  1601. text.ReleaseWrite;
  1602. t.ReleaseRead;
  1603. END;
  1604. ELSE
  1605. res := FileNotFound;
  1606. END;
  1607. ELSE
  1608. res := CodecNotFound;
  1609. END;
  1610. END Load;
  1611. (** Import text in ASCII format. *)
  1612. PROCEDURE LoadAscii*(text : Text; CONST filename : ARRAY OF CHAR; VAR res : WORD);
  1613. BEGIN
  1614. Load(text, filename, "ISO8859-1", res)
  1615. END LoadAscii;
  1616. (** Import text in UTF8 format. *)
  1617. PROCEDURE LoadUTF8*(text : Text; CONST filename : ARRAY OF CHAR; VAR res : WORD);
  1618. BEGIN
  1619. Load(text, filename, "UTF-8", res)
  1620. END LoadUTF8;
  1621. (** import text in UCS16 format *)
  1622. PROCEDURE LoadUCS16*(text : Text; CONST filename : ARRAY OF CHAR; VAR res : WORD);
  1623. VAR f : Files.File; r : Files.Reader;
  1624. i, m : LONGINT;
  1625. tempUCS32 : ARRAY 1024 OF Char32;
  1626. ch, last : Char32; tc1, tc2 : CHAR;
  1627. BEGIN
  1628. text.AcquireWrite;
  1629. res := -1;
  1630. f := Files.Old(filename);
  1631. IF f # NIL THEN
  1632. m := LEN(tempUCS32) - 1;
  1633. Files.OpenReader(r, f, 0);
  1634. i := 0;
  1635. REPEAT
  1636. r.Char(tc1); r.Char(tc2); ch := ORD(tc1) * 256 + ORD(tc2);
  1637. IF i = m THEN tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32); i := 0 END;
  1638. IF (last # ORD(CR)) OR (ch # ORD(LF)) THEN
  1639. IF ch = ORD(CR) THEN tempUCS32[i] := ORD(LF)
  1640. ELSE tempUCS32[i] := ch
  1641. END;
  1642. INC(i)
  1643. END;
  1644. last := ch
  1645. UNTIL (r.res # Streams.Ok);
  1646. tempUCS32[i] := 0; text.InsertUCS32(text.GetLength(), tempUCS32);
  1647. res := Ok;
  1648. ELSE
  1649. res := FileNotFound;
  1650. END;
  1651. text.ReleaseWrite;
  1652. END LoadUCS16;
  1653. (** Import an Oberon Text *)
  1654. PROCEDURE LoadOberonText*(text: Text; CONST fileName: ARRAY OF CHAR; VAR res: WORD);
  1655. BEGIN
  1656. Load(text, fileName, "Oberon", res)
  1657. END LoadOberonText;
  1658. (** Import a BBT Text *)
  1659. PROCEDURE LoadText*(text : Texts.Text; CONST filename : ARRAY OF CHAR; VAR res : WORD);
  1660. BEGIN
  1661. Load(text, filename, "BBT", res)
  1662. END LoadText;
  1663. (** store text using codecs *)
  1664. PROCEDURE Store*(text : Text; CONST filename, format : ARRAY OF CHAR; VAR res : WORD);
  1665. VAR file : Files.File; w : Files.Writer; encoder : Codecs.TextEncoder;
  1666. BEGIN
  1667. ASSERT(text # NIL);
  1668. encoder := Codecs.GetTextEncoder(format);
  1669. IF (encoder # NIL) THEN
  1670. file := Files.New(filename);
  1671. IF (file # NIL) THEN
  1672. NEW(w, file, 0);
  1673. text.AcquireRead;
  1674. encoder.Open(w);
  1675. encoder.WriteText(text, res);
  1676. text.ReleaseRead;
  1677. IF (res = Ok) THEN
  1678. Files.Register(file); file.Update;
  1679. END;
  1680. ELSE
  1681. res := FileCreationError;
  1682. END;
  1683. ELSE
  1684. res := CodecNotFound;
  1685. END;
  1686. END Store;
  1687. (** Export text in ASCII format. Objects, attributes and characters > CHR(128) are lost *)
  1688. PROCEDURE ExportAscii*(text : Text; CONST fileName : ARRAY OF CHAR; VAR res : WORD);
  1689. BEGIN
  1690. Store(text, fileName, "ISO8859-1", res)
  1691. END ExportAscii;
  1692. (** Export text in UTF8 format Objects and attributes are lost *)
  1693. PROCEDURE ExportUTF8*(text : Text; CONST fileName : ARRAY OF CHAR; VAR res : WORD);
  1694. BEGIN
  1695. Store(text, fileName, "UTF-8", res)
  1696. END ExportUTF8;
  1697. (** Export text in Oberon format Objects are lost *)
  1698. PROCEDURE StoreOberonText*(text : Text; CONST fileName: ARRAY OF CHAR; VAR res : WORD);
  1699. BEGIN
  1700. Store(text, fileName, "Oberon", res)
  1701. END StoreOberonText;
  1702. (** Export text in Bluebottle format *)
  1703. PROCEDURE StoreText*(text : Texts.Text; CONST fileName : ARRAY OF CHAR; VAR res : WORD);
  1704. BEGIN
  1705. Store(text, fileName, "BBT", res)
  1706. END StoreText;
  1707. (** Text to UTF8 string. Objects and attributes are lost. The String is truncated if buffer is too small *)
  1708. PROCEDURE TextToStr*(text : Text; VAR string : ARRAY OF CHAR);
  1709. VAR i, l, pos : LONGINT; r : Texts.TextReader; ch : Texts.Char32; ok : BOOLEAN;
  1710. BEGIN
  1711. text.AcquireRead;
  1712. COPY("", string);
  1713. NEW(r, text);
  1714. i := 0; l := text.GetLength(); pos := 0; ok := TRUE;
  1715. WHILE (i < l) & ok DO
  1716. r.ReadCh(ch);
  1717. IF (ch > 0) THEN ok := UTF8Strings.EncodeChar(ch, string, pos) END;
  1718. INC(i)
  1719. END;
  1720. text.ReleaseRead
  1721. END TextToStr;
  1722. (** Write <length> characters starting at <start> to stream <w>. Objects and attributes are lost
  1723. Caller MUST HOLD lock!!! *)
  1724. PROCEDURE SubTextToStream*(text : Text; start, length : LONGINT; w : Streams.Writer);
  1725. VAR r : Texts.TextReader; ok : BOOLEAN; ch : Texts.Char32; buffer : ARRAY 6 OF CHAR; i : LONGINT;
  1726. BEGIN
  1727. ASSERT((text # NIL) & (text.HasReadLock()));
  1728. ASSERT((0 <= start) & (length >= 0) & (start + length <= text.GetLength()));
  1729. ASSERT(w # NIL);
  1730. IF (length > 0) THEN
  1731. NEW(r, text);
  1732. r.SetPosition(start);
  1733. ok := TRUE;
  1734. r.ReadCh(ch);
  1735. WHILE (length > 0) & (w.res = Streams.Ok) DO
  1736. ASSERT(ch # 0); (* we already checked start + length <= text.GetLength()) *)
  1737. i := 0;
  1738. ok := UTF8Strings.EncodeChar(ch, buffer, i);
  1739. ASSERT(ok & (i < LEN(buffer))); (* buffer is always large enough *)
  1740. buffer[i] := 0X;
  1741. w.String(buffer);
  1742. r.ReadCh(ch); (* we may read past start + length / end-of-text *)
  1743. DEC(length);
  1744. END;
  1745. END;
  1746. END SubTextToStream;
  1747. (** Text to stream as UTF-8. Objects and attributes are lost. *)
  1748. PROCEDURE TextToStream*(text : Text; w : Streams.Writer);
  1749. VAR length : LONGINT;
  1750. BEGIN
  1751. ASSERT((text # NIL) & (w # NIL));
  1752. text.AcquireRead;
  1753. length := text.GetLength();
  1754. IF (length > 0) THEN
  1755. SubTextToStream(text, 0, length, w);
  1756. END;
  1757. text.ReleaseRead;
  1758. END TextToStream;
  1759. (** Text to UTF8 string. Objects and attributes are lost. The String is truncated if buffer is too small *)
  1760. PROCEDURE SubTextToStrAt*(text : Text; startPos, len : LONGINT; VAR index : LONGINT; VAR string : ARRAY OF CHAR);
  1761. VAR i, length, pos : LONGINT; r : Texts.TextReader; ch : Texts.Char32; ok : BOOLEAN;
  1762. BEGIN
  1763. ASSERT((0 <= index) & (index < LEN(string)));
  1764. text.AcquireRead;
  1765. string[index] := 0X;
  1766. NEW(r, text);
  1767. r.SetPosition(startPos);
  1768. i := 0; length := len; pos := index; ok := TRUE;
  1769. WHILE (i < length) & ok DO
  1770. r.ReadCh(ch);
  1771. IF (ch > 0) THEN ok := UTF8Strings.EncodeChar(ch, string, pos) END;
  1772. INC(i);
  1773. END;
  1774. IF (pos < LEN(string)) THEN
  1775. index := pos;
  1776. ELSE
  1777. index := LEN(string)-1;
  1778. string[index] := 0X;
  1779. END;
  1780. text.ReleaseRead;
  1781. ASSERT((0 <= index) & (index < LEN(string)));
  1782. END SubTextToStrAt;
  1783. (** Text to UTF8 string. Objects and attributes are lost. The String is truncated if buffer is too small *)
  1784. PROCEDURE SubTextToStr*(text : Text; startPos, len : LONGINT; VAR string : ARRAY OF CHAR);
  1785. VAR index : LONGINT;
  1786. BEGIN
  1787. index := 0;
  1788. SubTextToStrAt(text, startPos, len, index, string);
  1789. END SubTextToStr;
  1790. (** insert utf8 string into text *)
  1791. PROCEDURE StrToText*(text : Text; pos : LONGINT; CONST string : ARRAY OF CHAR);
  1792. VAR r : Streams.StringReader;
  1793. i, m: LONGINT;
  1794. tempUCS32 : ARRAY 1024 OF Char32;
  1795. ch, last : Texts.Char32;
  1796. BEGIN
  1797. text.AcquireWrite;
  1798. NEW(r, LEN(string));
  1799. m := LEN(tempUCS32) - 1;
  1800. r.Set(string);
  1801. i := 0;
  1802. REPEAT
  1803. IF GetUTF8Char(r, ch) THEN
  1804. IF i = m THEN tempUCS32[i] := 0; text.InsertUCS32(pos, tempUCS32); INC(pos, m); i := 0 END;
  1805. IF (last # ORD(CR)) OR (ch # ORD(LF)) THEN
  1806. IF ch = ORD(CR) THEN tempUCS32[i] := ORD(LF)
  1807. ELSE tempUCS32[i] := ch
  1808. END;
  1809. INC(i)
  1810. END;
  1811. last := ch
  1812. END
  1813. UNTIL (r.res # Streams.Ok);
  1814. tempUCS32[i] := 0; text.InsertUCS32(pos, tempUCS32);
  1815. text.ReleaseWrite
  1816. END StrToText;
  1817. PROCEDURE IsDigit( ch: CHAR ): BOOLEAN;
  1818. BEGIN
  1819. RETURN (ch >= '0') & (ch <= '9')
  1820. END IsDigit;
  1821. PROCEDURE DecodeOberonFontName(CONST name : ARRAY OF CHAR; VAR fn : ARRAY OF CHAR; VAR size : LONGINT; VAR style : SET);
  1822. VAR i, j: LONGINT; sizeStr : ARRAY 8 OF CHAR;
  1823. BEGIN
  1824. (* first name in oberon font names is capital, all following are non-capital *)
  1825. fn[0] := name[0];
  1826. i := 1; WHILE ~IsDigit(name[i]) DO fn[i] := name[i]; INC(i) END; fn[i] := 0X;
  1827. (* read the size *)
  1828. j := 0; WHILE IsDigit(name[i]) DO sizeStr[j] := name[i]; INC(j); INC(i) END; sizeStr[j] := 0X;
  1829. Strings.StrToInt(sizeStr, size);
  1830. style := {};
  1831. CASE CAP(name[i]) OF
  1832. | "I" : INCL(style, WMGraphics.FontItalic);
  1833. | "B" : INCL(style, WMGraphics.FontBold);
  1834. ELSE
  1835. END
  1836. END DecodeOberonFontName;
  1837. PROCEDURE ToOberonFont(CONST name : ARRAY OF CHAR; size : LONGINT; style : SET; VAR oname : ARRAY OF CHAR) : BOOLEAN;
  1838. VAR str : ARRAY 32 OF CHAR; f: Files.File;
  1839. BEGIN
  1840. COPY(name, oname);
  1841. Strings.IntToStr(size, str); Strings.Append(oname, str);
  1842. IF WMGraphics.FontBold IN style THEN Strings.Append(oname, "b") END;
  1843. IF WMGraphics.FontItalic IN style THEN Strings.Append(oname, "i") END;
  1844. Strings.Append(oname, ".Scn.Fnt");
  1845. f := Files.Old(oname);
  1846. IF f # NIL THEN RETURN TRUE
  1847. ELSE
  1848. IF oberonFontAllocatable # NIL THEN
  1849. RETURN oberonFontAllocatable(oname)
  1850. END;
  1851. RETURN FALSE
  1852. END
  1853. END ToOberonFont;
  1854. PROCEDURE GetUTF8Char*(r : Streams.Reader; VAR u : Texts.Char32) : BOOLEAN;
  1855. VAR ch : ARRAY 8 OF CHAR; i : LONGINT;
  1856. BEGIN
  1857. ch[0] := r.Get();
  1858. FOR i := 1 TO ORD(UTF8Strings.CodeLength[ORD(ch[0])]) - 1 DO ch[i] := r.Get() END;
  1859. i := 0;
  1860. RETURN UTF8Strings.DecodeChar(ch, i, u)
  1861. END GetUTF8Char;
  1862. PROCEDURE WriteUTF8Char*(w : Streams.Writer; ch : Char32);
  1863. VAR str : ARRAY 8 OF CHAR; i : LONGINT;
  1864. BEGIN
  1865. i := 0; IF UTF8Strings.EncodeChar(ch, str, i) THEN w.Bytes(str, 0, i) END
  1866. END WriteUTF8Char;
  1867. (* Style to Attribute Converter *)
  1868. PROCEDURE StyleToAttribute*(style: Texts.CharacterStyle): Texts.Attributes;
  1869. VAR attr: Texts.Attributes; fi: Texts.FontInfo;
  1870. BEGIN
  1871. IF (style = NIL) THEN RETURN NIL END;
  1872. NEW(attr); NEW(fi);
  1873. COPY(style.family, fi.name);
  1874. fi.size := ENTIER(FP1616.FixpToFloat(style.size));
  1875. fi.style := style.style;
  1876. attr.color := style.color;
  1877. attr.bgcolor := style.bgColor;
  1878. attr.voff := ENTIER(FP1616.FixpToFloat(style.baselineShift));
  1879. attr.fontInfo := fi;
  1880. RETURN attr
  1881. END StyleToAttribute;
  1882. (* Attribute To Style Converter, creates style with given name *)
  1883. PROCEDURE AttributeToStyle*(CONST name: ARRAY OF CHAR; attr: Texts.Attributes): Texts.CharacterStyle;
  1884. VAR style: Texts.CharacterStyle;
  1885. BEGIN
  1886. NEW(style);
  1887. COPY(name, style.name);
  1888. IF attr.fontInfo # NIL THEN
  1889. COPY(attr.fontInfo.name, style.family);
  1890. style.size := FP1616.FloatToFixp(attr.fontInfo.size*1.0);
  1891. style.style := attr.fontInfo.style;
  1892. ELSE
  1893. COPY("Oberon", style.family);
  1894. style.size := FP1616.FloatToFixp(12.0);
  1895. style.style := {};
  1896. END;
  1897. style.color := attr.color;
  1898. style.bgColor := attr.bgcolor;
  1899. style.baselineShift := attr.voff;
  1900. RETURN style
  1901. END AttributeToStyle;
  1902. (**
  1903. * -- Bluebottle File Format --
  1904. * Convert Procedure version: 0.1
  1905. * Usage: Convert file1.Mod file2.Mod ... fileN.Mod~
  1906. *)
  1907. PROCEDURE Convert*(context : Commands.Context);
  1908. VAR filename : Files.FileName;
  1909. BEGIN
  1910. context.out.String("-- Oberon To Bluebottle File Converter v0.1 --"); context.out.Ln;
  1911. WHILE context.arg.GetString(filename) DO
  1912. ConvertFile(filename, context);
  1913. END;
  1914. context.out.String("-- all done --"); context.out.Ln;
  1915. END Convert;
  1916. PROCEDURE ConvertAll*(context : Commands.Context);
  1917. VAR enumerator : Files.Enumerator;
  1918. filename : Files.FileName; flags : SET; time, date, size : LONGINT;
  1919. BEGIN
  1920. NEW(enumerator);
  1921. enumerator.Open("", {});
  1922. context.out.String("-- Oberon To Bluebottle File Converter v0.1 --"); context.out.Ln;
  1923. WHILE enumerator.HasMoreEntries() DO
  1924. IF enumerator.GetEntry(filename, flags, time, date, size) THEN
  1925. IF Strings.Match("*.Mod", filename) THEN
  1926. ConvertFile(filename, context);
  1927. END;
  1928. END;
  1929. END;
  1930. context.out.String("-- all done --"); context.out.Ln;
  1931. enumerator.Close;
  1932. END ConvertAll;
  1933. (* Converts the file with the given name into bb file format *)
  1934. PROCEDURE ConvertFile(CONST file: ARRAY OF CHAR; context : Commands.Context);
  1935. VAR ext, ext2: ARRAY 16 OF CHAR; file2 : ARRAY 256 OF CHAR;
  1936. text : Texts.Text; res : WORD;
  1937. BEGIN
  1938. ext2 := "mod"; (* extension for the converted files *)
  1939. Strings.GetExtension(file, file2, ext);
  1940. Strings.Append(file2, "."); Strings.Append(file2, ext2);
  1941. (* check if file is Module *)
  1942. IF (ext = "Mod") THEN
  1943. NEW(text);
  1944. context.out.String("Converting: "); context.out.String(file);
  1945. (* read Oberon Format file *)
  1946. text.AcquireWrite;
  1947. LoadOberonText(text, file, res);
  1948. text.ReleaseWrite;
  1949. IF (res = 0) THEN
  1950. (* write Bluebottle Format File *)
  1951. text.AcquireRead;
  1952. StoreText(text, file2, res);
  1953. text.ReleaseRead;
  1954. IF (res # 0) THEN
  1955. context.error.String("Converter ERROR: Something went wrong... "); context.error.Ln;
  1956. ELSE
  1957. context.out.String(" done"); context.out.Ln;
  1958. END;
  1959. ELSE
  1960. context.error.String("Converter ERROR: Couldn't load Oberon File: "); context.error.String(file); context.error.Ln;
  1961. END;
  1962. ELSE
  1963. context.error.String("Converter ERROR: Wrong Extension: "); context.error.String(file); context.error.Ln;
  1964. END;
  1965. END ConvertFile;
  1966. (* ------------------------------------------------------------------------- *)
  1967. PROCEDURE SkipLine(utilreader: Texts.TextReader; pos: LONGINT): LONGINT;
  1968. VAR ch : Texts.Char32;
  1969. BEGIN
  1970. utilreader.SetPosition(pos );
  1971. utilreader.SetDirection(1);
  1972. utilreader.ReadCh(ch);
  1973. WHILE (ch # Texts.NewLineChar) & (~utilreader.eot) DO utilreader.ReadCh(ch) END;
  1974. RETURN utilreader.GetPosition()
  1975. END SkipLine;
  1976. PROCEDURE IndentText*(text : Texts.Text; from, to : LONGINT; minus : BOOLEAN);
  1977. VAR r : Texts.TextReader;
  1978. p, pto : Texts.TextPosition;
  1979. tab : ARRAY 2 OF Texts.Char32;
  1980. c : Texts.Char32;
  1981. BEGIN
  1982. tab[0] := Texts.TabChar; tab[1] := 0;
  1983. text.AcquireWrite;
  1984. NEW(r, text); NEW(p, text); NEW(pto, text);
  1985. pto.SetPosition(to);
  1986. p.SetPosition(from);
  1987. WHILE p.GetPosition() < pto.GetPosition() DO
  1988. p.SetPosition(FindPosLineStart(r, p.GetPosition()));
  1989. IF minus THEN
  1990. r.SetPosition(p.GetPosition()); r.SetDirection(1);
  1991. r.ReadCh(c);
  1992. IF c = Texts.TabChar THEN
  1993. text.Delete(p.GetPosition(), 1)
  1994. END
  1995. ELSIF SkipLine(r, p.GetPosition()) > p.GetPosition() + 1 THEN
  1996. text.InsertUCS32(p.GetPosition(), tab);
  1997. END;
  1998. p.SetPosition(SkipLine(r, p.GetPosition()))
  1999. END;
  2000. text.ReleaseWrite
  2001. END IndentText;
  2002. PROCEDURE UCS32StrLength*(CONST string: ARRAY OF Char32): LONGINT;
  2003. VAR len: LONGINT;
  2004. BEGIN
  2005. len := 0; WHILE (string[len] # 0) DO INC(len) END;
  2006. RETURN len
  2007. END UCS32StrLength;
  2008. (** returns the position of the first occurrence of pattern (ucs32) in the text or -1 if no occurrence is found *)
  2009. (* Rabin-Karp algorithm, adopted from Sedgewick *)
  2010. (* efficiency could be improved by not seeking so much *)
  2011. PROCEDURE Pos*(CONST pattern: ARRAY OF Char32; from : LONGINT; text : Text): LONGINT;
  2012. CONST
  2013. q = 8204957; (* prime number, {(d+1) * q <= MAX(LONGINT)} *)
  2014. d = 256; (* number of different characters *)
  2015. VAR h1, h2, dM, i, j, m, n: LONGINT; ch : Char32; found : BOOLEAN; r : Texts.TextReader;
  2016. BEGIN (* caller must hold read lock on text *)
  2017. m := UCS32StrLength(pattern); n := text.GetLength();
  2018. IF (from + m > n) THEN RETURN -1 END;
  2019. NEW(r, text); r.SetPosition(from);
  2020. dM := 1; FOR i := 0 TO m-2 DO dM := (d*dM) MOD q END;
  2021. h1 := 0; FOR i := 0 TO m-1 DO h1 := (h1*d + (pattern[i] MOD d)) MOD q END;
  2022. h2 := 0; FOR i := 0 TO m-1 DO r.ReadCh(ch); ch := ch MOD d; h2 := (h2*d + ch) MOD q END;
  2023. i := from; found := FALSE;
  2024. IF (h1 = h2) THEN (* verify *)
  2025. j := 0; r.SetPosition(i); found := TRUE;
  2026. WHILE (j < m) DO
  2027. r.ReadCh(ch);
  2028. IF (ch # pattern[j]) THEN found := FALSE; j := m; END; (* hash values are equal, but strings are not *)
  2029. INC(j);
  2030. END;
  2031. END;
  2032. WHILE ~found & (i < n-m) DO
  2033. r.SetPosition(i); r.ReadCh(ch); ch := ch MOD d; h2 := (h2 + d*q - ch*dM) MOD q;
  2034. r.SetPosition(i + m); r.ReadCh(ch); ch := ch MOD d; h2 := (h2*d + ch) MOD q;
  2035. INC(i);
  2036. IF (h1 = h2) THEN (* verify *)
  2037. j := 0; r.SetPosition(i); found := TRUE;
  2038. WHILE (j < m) DO
  2039. r.ReadCh(ch);
  2040. IF (ch # pattern[j]) THEN found := FALSE; j := m; END; (* hash values are equal, but strings are not *)
  2041. INC(j);
  2042. END;
  2043. END;
  2044. END;
  2045. IF found THEN RETURN i
  2046. ELSE RETURN -1
  2047. END
  2048. END Pos;
  2049. PROCEDURE UpperCaseChar32*(VAR ch : Texts.Char32);
  2050. BEGIN
  2051. (* LONGINT version of IF (ch >= "a") & (ch <= "z") THEN CAP(ch); END; *)
  2052. IF (ch >= 61H) & (ch <= 7AH) THEN ch := ch - 32; END;
  2053. END UpperCaseChar32;
  2054. (* Compare the pattern string of length 'length' with the string at the current position/direction of the text reader 'r' *)
  2055. PROCEDURE Equals(CONST pattern : ARRAY OF Char32; r : Texts.TextReader; length : LONGINT; ignoreCase : BOOLEAN) : BOOLEAN;
  2056. VAR ch, chp : Texts.Char32; equals : BOOLEAN; i : LONGINT;
  2057. BEGIN
  2058. i := 0; equals := TRUE;
  2059. WHILE (i < length) DO
  2060. r.ReadCh(ch); chp := pattern[i];
  2061. IF ignoreCase THEN UpperCaseChar32(ch); UpperCaseChar32(chp); END;
  2062. IF (ch # chp) THEN equals := FALSE; i := length; END; (* hash values are equal, but strings are not *)
  2063. INC(i);
  2064. END;
  2065. RETURN equals;
  2066. END Equals;
  2067. (** More generic version of Pos. Basically the same search algorithm, but can also perform case-insensitive searching and/or
  2068. * backwards directed searching.
  2069. * Returns the position of the first character of the first occurence of 'pattern' in 'text' in search direction or -1 if pattern not found
  2070. *)
  2071. PROCEDURE GenericPos*(CONST pattern: ARRAY OF Char32; from : LONGINT; text : Text; ignoreCase, backwards : BOOLEAN): LONGINT;
  2072. CONST
  2073. q = 8204957; (* prime number, {(d+1) * q <= MAX(LONGINT)} *)
  2074. d = 256; (* number of different characters *)
  2075. VAR h1, h2, dM, i, patternLength, stringLength: LONGINT; ch : Char32; found : BOOLEAN; r : Texts.TextReader;
  2076. BEGIN (* caller must hold read lock on text *)
  2077. patternLength := UCS32StrLength(pattern); stringLength := text.GetLength();
  2078. (* check whether the search pattern can be contained in the text regarding the search direction *)
  2079. IF backwards THEN
  2080. IF (patternLength > from + 1) THEN RETURN -1; END;
  2081. ELSE
  2082. IF (from + patternLength > stringLength) THEN RETURN -1; END;
  2083. END;
  2084. dM := 1; FOR i := 0 TO patternLength-2 DO dM := (d*dM) MOD q END;
  2085. (* calculate hash value for search pattern string *)
  2086. h1 := 0;
  2087. FOR i := 0 TO patternLength-1 DO
  2088. IF backwards THEN
  2089. ch := pattern[patternLength-1-i];
  2090. ELSE
  2091. ch := pattern[i];
  2092. END;
  2093. IF ignoreCase THEN UpperCaseChar32(ch); END;
  2094. ch := ch MOD d;
  2095. h1 := (h1*d + ch) MOD q;
  2096. END;
  2097. (* calculate hash value for the first 'patternLength' characters of the text to be searched *)
  2098. NEW(r, text); r.SetPosition(from);
  2099. IF backwards THEN r.SetDirection(-1); END;
  2100. h2 := 0;
  2101. FOR i := 0 TO patternLength-1 DO
  2102. r.ReadCh(ch);
  2103. IF ignoreCase THEN UpperCaseChar32(ch); END;
  2104. ch := ch MOD d;
  2105. h2 := (h2*d + ch) MOD q;
  2106. END;
  2107. i := from; found := FALSE;
  2108. IF (h1 = h2) THEN (* Hash values match, compare strings *)
  2109. IF backwards THEN
  2110. r.SetDirection(1); r.SetPosition(i - patternLength + 1);
  2111. ELSE
  2112. r.SetPosition(i);
  2113. END;
  2114. found := Equals(pattern, r, patternLength, ignoreCase);
  2115. IF backwards THEN r.SetDirection(-1); END;
  2116. END;
  2117. LOOP
  2118. (* check wether we're finished *)
  2119. IF found THEN EXIT; END;
  2120. IF backwards THEN
  2121. IF (i < patternLength) THEN EXIT; END;
  2122. ELSE
  2123. IF (i >= stringLength-patternLength) THEN EXIT; END;
  2124. END;
  2125. (* remove last character from hash value *)
  2126. r.SetPosition(i); r.ReadCh(ch);
  2127. IF ignoreCase THEN UpperCaseChar32(ch); END;
  2128. ch := ch MOD d;
  2129. h2 := (h2 + d*q - ch*dM) MOD q;
  2130. (* add next character to hash value *)
  2131. IF backwards THEN
  2132. r.SetPosition(i - patternLength);
  2133. ELSE
  2134. r.SetPosition(i + patternLength);
  2135. END;
  2136. r.ReadCh(ch);
  2137. IF ignoreCase THEN UpperCaseChar32(ch); END;
  2138. ch := ch MOD d;
  2139. h2 := (h2*d + ch) MOD q;
  2140. IF backwards THEN
  2141. DEC(i);
  2142. ELSE
  2143. INC(i);
  2144. END;
  2145. IF (h1 = h2) THEN (* verify *)
  2146. IF backwards THEN
  2147. r.SetDirection(1); r.SetPosition(i - patternLength + 1);
  2148. ELSE
  2149. r.SetPosition(i);
  2150. END;
  2151. found := Equals(pattern, r, patternLength, ignoreCase);
  2152. IF backwards THEN r.SetDirection(-1); END;
  2153. END;
  2154. END;
  2155. IF found THEN
  2156. IF backwards THEN RETURN i - patternLength + 1;
  2157. ELSE RETURN i;
  2158. END;
  2159. ELSE RETURN -1;
  2160. END;
  2161. END GenericPos;
  2162. PROCEDURE Replace*(CONST string, by :Texts.UCS32String; text : Texts.Text; VAR nofReplacements : LONGINT);
  2163. VAR pos, stringLen, byLen : LONGINT;
  2164. BEGIN
  2165. ASSERT(text # NIL);
  2166. nofReplacements := 0;
  2167. stringLen := UCS32StrLength(string);
  2168. byLen := UCS32StrLength(by);
  2169. text.AcquireWrite;
  2170. pos := Pos(string, 0, text);
  2171. WHILE (pos > 0) DO
  2172. INC(nofReplacements);
  2173. text.Delete(pos, stringLen);
  2174. text.InsertUCS32(pos, by);
  2175. pos := Pos(string, pos + byLen, text);
  2176. END;
  2177. text.ReleaseWrite;
  2178. END Replace;
  2179. PROCEDURE AddFontFormat*(x : FormatDescriptor);
  2180. BEGIN
  2181. IF x.name # NIL THEN KernelLog.String("name = "); KernelLog.String(x.name^); KernelLog.Ln END;
  2182. IF x.loadProc # NIL THEN KernelLog.String("loadProc = "); KernelLog.String(x.loadProc^); KernelLog.Ln END;
  2183. IF x.storeProc # NIL THEN KernelLog.String("storeProc = "); KernelLog.String(x.storeProc^); KernelLog.Ln END;
  2184. END AddFontFormat;
  2185. PROCEDURE GetConfig;
  2186. VAR sectFM, e : XML.Element;
  2187. p : ANY; enum: XMLObjects.Enumerator;
  2188. f : FormatDescriptor;
  2189. BEGIN
  2190. IF Configuration.config # NIL THEN
  2191. sectFM := Configuration.GetNamedElement(Configuration.config.GetRoot(), "Section", "TextFormats");
  2192. ELSE
  2193. sectFM := NIL;
  2194. END;
  2195. IF sectFM # NIL THEN
  2196. enum := sectFM.GetContents();
  2197. IF enum # NIL THEN
  2198. WHILE enum.HasMoreElements() DO
  2199. p := enum.GetNext();
  2200. IF p IS XML.Element THEN
  2201. NEW(f);
  2202. f.name := p(XML.Element).GetName();
  2203. e := Configuration.GetNamedElement(p(XML.Element), "Setting", "Load");
  2204. IF e # NIL THEN f.loadProc := e.GetAttributeValue("Value") END;
  2205. e := Configuration.GetNamedElement(p(XML.Element), "Setting", "Store");
  2206. IF e # NIL THEN f.storeProc := e.GetAttributeValue("Value") END;
  2207. AddFontFormat(f);
  2208. END
  2209. END
  2210. END;
  2211. END
  2212. END GetConfig;
  2213. (* Oberon File Format *)
  2214. PROCEDURE OberonDecoderFactory*() : Codecs.TextDecoder;
  2215. VAR p : OberonDecoder;
  2216. BEGIN
  2217. NEW(p);
  2218. RETURN p
  2219. END OberonDecoderFactory;
  2220. PROCEDURE OberonEncoderFactory*() : Codecs.TextEncoder;
  2221. VAR p : OberonEncoder;
  2222. BEGIN
  2223. NEW(p);
  2224. RETURN p
  2225. END OberonEncoderFactory;
  2226. (* Bluebottle File Format *)
  2227. PROCEDURE BluebottleDecoderFactory*() : Codecs.TextDecoder;
  2228. VAR p : BluebottleDecoder;
  2229. BEGIN
  2230. NEW(p);
  2231. RETURN p
  2232. END BluebottleDecoderFactory;
  2233. PROCEDURE BluebottleEncoderFactory*() : Codecs.TextEncoder;
  2234. VAR p : BluebottleEncoder;
  2235. BEGIN
  2236. NEW(p);
  2237. RETURN p
  2238. END BluebottleEncoderFactory;
  2239. (* UTF-8 File Format *)
  2240. PROCEDURE UTF8DecoderFactory*() : Codecs.TextDecoder;
  2241. VAR p : UTF8Decoder;
  2242. BEGIN
  2243. NEW(p);
  2244. RETURN p
  2245. END UTF8DecoderFactory;
  2246. PROCEDURE UTF8EncoderFactory*() : Codecs.TextEncoder;
  2247. VAR p : UTF8Encoder;
  2248. BEGIN
  2249. NEW(p);
  2250. RETURN p
  2251. END UTF8EncoderFactory;
  2252. (* ISO8859-1 File Format *)
  2253. PROCEDURE ISO88591DecoderFactory*() : Codecs.TextDecoder;
  2254. VAR p : ISO88591Decoder;
  2255. BEGIN
  2256. NEW(p);
  2257. RETURN p
  2258. END ISO88591DecoderFactory;
  2259. PROCEDURE ISO88591EncoderFactory*() : Codecs.TextEncoder;
  2260. VAR p : ISO88591Encoder;
  2261. BEGIN
  2262. NEW(p);
  2263. RETURN p
  2264. END ISO88591EncoderFactory;
  2265. (* Hex File Format *)
  2266. PROCEDURE HEXDecoderFactory*() : Codecs.TextDecoder;
  2267. VAR p : HEXDecoder;
  2268. BEGIN
  2269. NEW(p);
  2270. RETURN p
  2271. END HEXDecoderFactory;
  2272. PROCEDURE HEXEncoderFactory*() : Codecs.TextEncoder;
  2273. VAR p : HEXEncoder;
  2274. BEGIN
  2275. NEW(p);
  2276. RETURN p
  2277. END HEXEncoderFactory;
  2278. PROCEDURE GetClipboard* (context: Commands.Context);
  2279. VAR r: TextReader;
  2280. BEGIN
  2281. NEW (r, Texts.clipboard);
  2282. Streams.Copy (r, context.out); context.out.Update;
  2283. END GetClipboard;
  2284. PROCEDURE SetClipboard* (context: Commands.Context);
  2285. VAR w: TextWriter;
  2286. BEGIN
  2287. NEW (w, Texts.clipboard);
  2288. Streams.Copy (context.in, w); w.Update;
  2289. END SetClipboard;
  2290. PROCEDURE GetTextReader* (CONST filename: ARRAY OF CHAR): Streams.Reader;
  2291. VAR
  2292. file: Files.File; fileReader: Files.Reader; offset: LONGINT;
  2293. text: Text; format: LONGINT; res: WORD; textReader: TextReader;
  2294. BEGIN
  2295. (* Optimisation: skip header of oberon files and return a file reader instead of default text reader*)
  2296. file := Files.Old (filename);
  2297. IF file = NIL THEN RETURN NIL END;
  2298. NEW (fileReader, file, 0);
  2299. IF (fileReader.Get () = 0F0X) & (fileReader.Get () = 001X) THEN
  2300. offset := ORD (fileReader.Get ());
  2301. INC (offset, LONG (ORD (fileReader.Get ())) * 0100H);
  2302. fileReader.SetPos(offset);
  2303. RETURN fileReader
  2304. ELSE
  2305. NEW (text);
  2306. LoadAuto (text, filename, format, res);
  2307. NEW (textReader, text);
  2308. RETURN textReader
  2309. END
  2310. END GetTextReader;
  2311. PROCEDURE GetDefaultAttributes* () : Texts.Attributes;
  2312. BEGIN
  2313. RETURN Texts.defaultAttributes.Clone();
  2314. END GetDefaultAttributes;
  2315. BEGIN
  2316. oberonFontAllocatable := NIL;
  2317. GetConfig;
  2318. END TextUtilities.
  2319. TextUtilities.ConvertAll~