TextUtilities.Mod 79 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583
  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 : LONGINT);
  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, fontColor, fontBgColor, fontVOff : LONGINT;
  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: LONGINT);
  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 : LONGINT);
  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, res: LONGINT );
  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: LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  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, res : LONGINT; 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, res); (* style *)
  748. IF (res = 0) THEN attr.fontInfo.style := {};
  749. ELSIF (res = 1) THEN attr.fontInfo.style := {0};
  750. ELSIF (res = 2) THEN attr.fontInfo.style := {1};
  751. ELSIF (res = 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 : LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  1376. VAR r : Texts.TextReader; ch : Texts.Char32; i, j, k : LONGINT;
  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, res: LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  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: LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  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 : LONGINT);
  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 DecodeOberonFontName(CONST name : ARRAY OF CHAR; VAR fn : ARRAY OF CHAR; VAR size : LONGINT; VAR style : SET);
  1818. VAR i, j: LONGINT; sizeStr : ARRAY 8 OF CHAR;
  1819. BEGIN
  1820. (* first name in oberon font names is capital, all following are non-capital *)
  1821. fn[0] := name[0];
  1822. i := 1; WHILE (name[i] >= "a") & (name[i] <= "z") DO fn[i] := name[i]; INC(i) END; fn[i] := 0X;
  1823. (* read the size *)
  1824. j := 0; WHILE (name[i] >= "0") & (name[i] <= "9") DO sizeStr[j] := name[i]; INC(j); INC(i) END; sizeStr[j] := 0X;
  1825. Strings.StrToInt(sizeStr, size);
  1826. style := {};
  1827. CASE CAP(name[i]) OF
  1828. | "I" : INCL(style, WMGraphics.FontItalic);
  1829. | "B" : INCL(style, WMGraphics.FontBold);
  1830. ELSE
  1831. END
  1832. END DecodeOberonFontName;
  1833. PROCEDURE ToOberonFont(CONST name : ARRAY OF CHAR; size : LONGINT; style : SET; VAR oname : ARRAY OF CHAR) : BOOLEAN;
  1834. VAR str : ARRAY 32 OF CHAR; f: Files.File;
  1835. BEGIN
  1836. COPY(name, oname);
  1837. Strings.IntToStr(size, str); Strings.Append(oname, str);
  1838. IF WMGraphics.FontBold IN style THEN Strings.Append(oname, "b") END;
  1839. IF WMGraphics.FontItalic IN style THEN Strings.Append(oname, "i") END;
  1840. Strings.Append(oname, ".Scn.Fnt");
  1841. f := Files.Old(oname);
  1842. IF f # NIL THEN RETURN TRUE
  1843. ELSE
  1844. IF oberonFontAllocatable # NIL THEN
  1845. RETURN oberonFontAllocatable(oname)
  1846. END;
  1847. RETURN FALSE
  1848. END
  1849. END ToOberonFont;
  1850. PROCEDURE GetUTF8Char*(r : Streams.Reader; VAR u : Texts.Char32) : BOOLEAN;
  1851. VAR ch : ARRAY 8 OF CHAR; i : LONGINT;
  1852. BEGIN
  1853. ch[0] := r.Get();
  1854. FOR i := 1 TO ORD(UTF8Strings.CodeLength[ORD(ch[0])]) - 1 DO ch[i] := r.Get() END;
  1855. i := 0;
  1856. RETURN UTF8Strings.DecodeChar(ch, i, u)
  1857. END GetUTF8Char;
  1858. PROCEDURE WriteUTF8Char*(w : Streams.Writer; ch : Char32);
  1859. VAR str : ARRAY 8 OF CHAR; i : LONGINT;
  1860. BEGIN
  1861. i := 0; IF UTF8Strings.EncodeChar(ch, str, i) THEN w.Bytes(str, 0, i) END
  1862. END WriteUTF8Char;
  1863. (* Style to Attribute Converter *)
  1864. PROCEDURE StyleToAttribute*(style: Texts.CharacterStyle): Texts.Attributes;
  1865. VAR attr: Texts.Attributes; fi: Texts.FontInfo;
  1866. BEGIN
  1867. IF (style = NIL) THEN RETURN NIL END;
  1868. NEW(attr); NEW(fi);
  1869. COPY(style.family, fi.name);
  1870. fi.size := ENTIER(FP1616.FixpToFloat(style.size));
  1871. fi.style := style.style;
  1872. attr.color := style.color;
  1873. attr.bgcolor := style.bgColor;
  1874. attr.voff := ENTIER(FP1616.FixpToFloat(style.baselineShift));
  1875. attr.fontInfo := fi;
  1876. RETURN attr
  1877. END StyleToAttribute;
  1878. (* Attribute To Style Converter, creates style with given name *)
  1879. PROCEDURE AttributeToStyle*(CONST name: ARRAY OF CHAR; attr: Texts.Attributes): Texts.CharacterStyle;
  1880. VAR style: Texts.CharacterStyle;
  1881. BEGIN
  1882. NEW(style);
  1883. COPY(name, style.name);
  1884. IF attr.fontInfo # NIL THEN
  1885. COPY(attr.fontInfo.name, style.family);
  1886. style.size := FP1616.FloatToFixp(attr.fontInfo.size*1.0);
  1887. style.style := attr.fontInfo.style;
  1888. ELSE
  1889. COPY("Oberon", style.family);
  1890. style.size := FP1616.FloatToFixp(12.0);
  1891. style.style := {};
  1892. END;
  1893. style.color := attr.color;
  1894. style.bgColor := attr.bgcolor;
  1895. style.baselineShift := attr.voff;
  1896. RETURN style
  1897. END AttributeToStyle;
  1898. (**
  1899. * -- Bluebottle File Format --
  1900. * Convert Procedure version: 0.1
  1901. * Usage: Convert file1.Mod file2.Mod ... fileN.Mod~
  1902. *)
  1903. PROCEDURE Convert*(context : Commands.Context);
  1904. VAR filename : Files.FileName;
  1905. BEGIN
  1906. context.out.String("-- Oberon To Bluebottle File Converter v0.1 --"); context.out.Ln;
  1907. WHILE context.arg.GetString(filename) DO
  1908. ConvertFile(filename, context);
  1909. END;
  1910. context.out.String("-- all done --"); context.out.Ln;
  1911. END Convert;
  1912. PROCEDURE ConvertAll*(context : Commands.Context);
  1913. VAR enumerator : Files.Enumerator;
  1914. filename : Files.FileName; flags : SET; time, date, size : LONGINT;
  1915. BEGIN
  1916. NEW(enumerator);
  1917. enumerator.Open("", {});
  1918. context.out.String("-- Oberon To Bluebottle File Converter v0.1 --"); context.out.Ln;
  1919. WHILE enumerator.HasMoreEntries() DO
  1920. IF enumerator.GetEntry(filename, flags, time, date, size) THEN
  1921. IF Strings.Match("*.Mod", filename) THEN
  1922. ConvertFile(filename, context);
  1923. END;
  1924. END;
  1925. END;
  1926. context.out.String("-- all done --"); context.out.Ln;
  1927. enumerator.Close;
  1928. END ConvertAll;
  1929. (* Converts the file with the given name into bb file format *)
  1930. PROCEDURE ConvertFile(CONST file: ARRAY OF CHAR; context : Commands.Context);
  1931. VAR ext, ext2: ARRAY 16 OF CHAR; file2 : ARRAY 256 OF CHAR;
  1932. text : Texts.Text; res : LONGINT;
  1933. BEGIN
  1934. ext2 := "mod"; (* extension for the converted files *)
  1935. Strings.GetExtension(file, file2, ext);
  1936. Strings.Append(file2, "."); Strings.Append(file2, ext2);
  1937. (* check if file is Module *)
  1938. IF (ext = "Mod") THEN
  1939. NEW(text);
  1940. context.out.String("Converting: "); context.out.String(file);
  1941. (* read Oberon Format file *)
  1942. text.AcquireWrite;
  1943. LoadOberonText(text, file, res);
  1944. text.ReleaseWrite;
  1945. IF (res = 0) THEN
  1946. (* write Bluebottle Format File *)
  1947. text.AcquireRead;
  1948. StoreText(text, file2, res);
  1949. text.ReleaseRead;
  1950. IF (res # 0) THEN
  1951. context.error.String("Converter ERROR: Something went wrong... "); context.error.Ln;
  1952. ELSE
  1953. context.out.String(" done"); context.out.Ln;
  1954. END;
  1955. ELSE
  1956. context.error.String("Converter ERROR: Couldn't load Oberon File: "); context.error.String(file); context.error.Ln;
  1957. END;
  1958. ELSE
  1959. context.error.String("Converter ERROR: Wrong Extension: "); context.error.String(file); context.error.Ln;
  1960. END;
  1961. END ConvertFile;
  1962. (* ------------------------------------------------------------------------- *)
  1963. PROCEDURE SkipLine(utilreader: Texts.TextReader; pos: LONGINT): LONGINT;
  1964. VAR ch : Texts.Char32;
  1965. BEGIN
  1966. utilreader.SetPosition(pos );
  1967. utilreader.SetDirection(1);
  1968. utilreader.ReadCh(ch);
  1969. WHILE (ch # Texts.NewLineChar) & (~utilreader.eot) DO utilreader.ReadCh(ch) END;
  1970. RETURN utilreader.GetPosition()
  1971. END SkipLine;
  1972. PROCEDURE IndentText*(text : Texts.Text; from, to : LONGINT; minus : BOOLEAN);
  1973. VAR r : Texts.TextReader;
  1974. p, pto : Texts.TextPosition;
  1975. tab : ARRAY 2 OF Texts.Char32;
  1976. c : Texts.Char32;
  1977. BEGIN
  1978. tab[0] := Texts.TabChar; tab[1] := 0;
  1979. text.AcquireWrite;
  1980. NEW(r, text); NEW(p, text); NEW(pto, text);
  1981. pto.SetPosition(to);
  1982. p.SetPosition(from);
  1983. WHILE p.GetPosition() < pto.GetPosition() DO
  1984. p.SetPosition(FindPosLineStart(r, p.GetPosition()));
  1985. IF minus THEN
  1986. r.SetPosition(p.GetPosition()); r.SetDirection(1);
  1987. r.ReadCh(c);
  1988. IF c = Texts.TabChar THEN
  1989. text.Delete(p.GetPosition(), 1)
  1990. END
  1991. ELSIF SkipLine(r, p.GetPosition()) > p.GetPosition() + 1 THEN
  1992. text.InsertUCS32(p.GetPosition(), tab);
  1993. END;
  1994. p.SetPosition(SkipLine(r, p.GetPosition()))
  1995. END;
  1996. text.ReleaseWrite
  1997. END IndentText;
  1998. PROCEDURE UCS32StrLength*(CONST string: ARRAY OF Char32): LONGINT;
  1999. VAR len: LONGINT;
  2000. BEGIN
  2001. len := 0; WHILE (string[len] # 0) DO INC(len) END;
  2002. RETURN len
  2003. END UCS32StrLength;
  2004. (** returns the position of the first occurrence of pattern (ucs32) in the text or -1 if no occurrence is found *)
  2005. (* Rabin-Karp algorithm, adopted from Sedgewick *)
  2006. (* efficiency could be improved by not seeking so much *)
  2007. PROCEDURE Pos*(CONST pattern: ARRAY OF Char32; from : LONGINT; text : Text): LONGINT;
  2008. CONST
  2009. q = 8204957; (* prime number, {(d+1) * q <= MAX(LONGINT)} *)
  2010. d = 256; (* number of different characters *)
  2011. VAR h1, h2, dM, i, j, m, n: LONGINT; ch : Char32; found : BOOLEAN; r : Texts.TextReader;
  2012. BEGIN (* caller must hold read lock on text *)
  2013. m := UCS32StrLength(pattern); n := text.GetLength();
  2014. IF (from + m > n) THEN RETURN -1 END;
  2015. NEW(r, text); r.SetPosition(from);
  2016. dM := 1; FOR i := 0 TO m-2 DO dM := (d*dM) MOD q END;
  2017. h1 := 0; FOR i := 0 TO m-1 DO h1 := (h1*d + (pattern[i] MOD d)) MOD q END;
  2018. h2 := 0; FOR i := 0 TO m-1 DO r.ReadCh(ch); ch := ch MOD d; h2 := (h2*d + ch) MOD q END;
  2019. i := from; found := FALSE;
  2020. IF (h1 = h2) THEN (* verify *)
  2021. j := 0; r.SetPosition(i); found := TRUE;
  2022. WHILE (j < m) DO
  2023. r.ReadCh(ch);
  2024. IF (ch # pattern[j]) THEN found := FALSE; j := m; END; (* hash values are equal, but strings are not *)
  2025. INC(j);
  2026. END;
  2027. END;
  2028. WHILE ~found & (i < n-m) DO
  2029. r.SetPosition(i); r.ReadCh(ch); ch := ch MOD d; h2 := (h2 + d*q - ch*dM) MOD q;
  2030. r.SetPosition(i + m); r.ReadCh(ch); ch := ch MOD d; h2 := (h2*d + ch) MOD q;
  2031. INC(i);
  2032. IF (h1 = h2) THEN (* verify *)
  2033. j := 0; r.SetPosition(i); found := TRUE;
  2034. WHILE (j < m) DO
  2035. r.ReadCh(ch);
  2036. IF (ch # pattern[j]) THEN found := FALSE; j := m; END; (* hash values are equal, but strings are not *)
  2037. INC(j);
  2038. END;
  2039. END;
  2040. END;
  2041. IF found THEN RETURN i
  2042. ELSE RETURN -1
  2043. END
  2044. END Pos;
  2045. PROCEDURE UpperCaseChar32*(VAR ch : Texts.Char32);
  2046. BEGIN
  2047. (* LONGINT version of IF (ch >= "a") & (ch <= "z") THEN CAP(ch); END; *)
  2048. IF (ch >= 61H) & (ch <= 7AH) THEN ch := ch - 32; END;
  2049. END UpperCaseChar32;
  2050. (* Compare the pattern string of length 'length' with the string at the current position/direction of the text reader 'r' *)
  2051. PROCEDURE Equals(CONST pattern : ARRAY OF Char32; r : Texts.TextReader; length : LONGINT; ignoreCase : BOOLEAN) : BOOLEAN;
  2052. VAR ch, chp : Texts.Char32; equals : BOOLEAN; i : LONGINT;
  2053. BEGIN
  2054. i := 0; equals := TRUE;
  2055. WHILE (i < length) DO
  2056. r.ReadCh(ch); chp := pattern[i];
  2057. IF ignoreCase THEN UpperCaseChar32(ch); UpperCaseChar32(chp); END;
  2058. IF (ch # chp) THEN equals := FALSE; i := length; END; (* hash values are equal, but strings are not *)
  2059. INC(i);
  2060. END;
  2061. RETURN equals;
  2062. END Equals;
  2063. (** More generic version of Pos. Basically the same search algorithm, but can also perform case-insensitive searching and/or
  2064. * backwards directed searching.
  2065. * Returns the position of the first character of the first occurence of 'pattern' in 'text' in search direction or -1 if pattern not found
  2066. *)
  2067. PROCEDURE GenericPos*(CONST pattern: ARRAY OF Char32; from : LONGINT; text : Text; ignoreCase, backwards : BOOLEAN): LONGINT;
  2068. CONST
  2069. q = 8204957; (* prime number, {(d+1) * q <= MAX(LONGINT)} *)
  2070. d = 256; (* number of different characters *)
  2071. VAR h1, h2, dM, i, patternLength, stringLength: LONGINT; ch : Char32; found : BOOLEAN; r : Texts.TextReader;
  2072. BEGIN (* caller must hold read lock on text *)
  2073. patternLength := UCS32StrLength(pattern); stringLength := text.GetLength();
  2074. (* check whether the search pattern can be contained in the text regarding the search direction *)
  2075. IF backwards THEN
  2076. IF (patternLength > from + 1) THEN RETURN -1; END;
  2077. ELSE
  2078. IF (from + patternLength > stringLength) THEN RETURN -1; END;
  2079. END;
  2080. dM := 1; FOR i := 0 TO patternLength-2 DO dM := (d*dM) MOD q END;
  2081. (* calculate hash value for search pattern string *)
  2082. h1 := 0;
  2083. FOR i := 0 TO patternLength-1 DO
  2084. IF backwards THEN
  2085. ch := pattern[patternLength-1-i];
  2086. ELSE
  2087. ch := pattern[i];
  2088. END;
  2089. IF ignoreCase THEN UpperCaseChar32(ch); END;
  2090. ch := ch MOD d;
  2091. h1 := (h1*d + ch) MOD q;
  2092. END;
  2093. (* calculate hash value for the first 'patternLength' characters of the text to be searched *)
  2094. NEW(r, text); r.SetPosition(from);
  2095. IF backwards THEN r.SetDirection(-1); END;
  2096. h2 := 0;
  2097. FOR i := 0 TO patternLength-1 DO
  2098. r.ReadCh(ch);
  2099. IF ignoreCase THEN UpperCaseChar32(ch); END;
  2100. ch := ch MOD d;
  2101. h2 := (h2*d + ch) MOD q;
  2102. END;
  2103. i := from; found := FALSE;
  2104. IF (h1 = h2) THEN (* Hash values match, compare strings *)
  2105. IF backwards THEN
  2106. r.SetDirection(1); r.SetPosition(i - patternLength + 1);
  2107. ELSE
  2108. r.SetPosition(i);
  2109. END;
  2110. found := Equals(pattern, r, patternLength, ignoreCase);
  2111. IF backwards THEN r.SetDirection(-1); END;
  2112. END;
  2113. LOOP
  2114. (* check wether we're finished *)
  2115. IF found THEN EXIT; END;
  2116. IF backwards THEN
  2117. IF (i < patternLength) THEN EXIT; END;
  2118. ELSE
  2119. IF (i >= stringLength-patternLength) THEN EXIT; END;
  2120. END;
  2121. (* remove last character from hash value *)
  2122. r.SetPosition(i); r.ReadCh(ch);
  2123. IF ignoreCase THEN UpperCaseChar32(ch); END;
  2124. ch := ch MOD d;
  2125. h2 := (h2 + d*q - ch*dM) MOD q;
  2126. (* add next character to hash value *)
  2127. IF backwards THEN
  2128. r.SetPosition(i - patternLength);
  2129. ELSE
  2130. r.SetPosition(i + patternLength);
  2131. END;
  2132. r.ReadCh(ch);
  2133. IF ignoreCase THEN UpperCaseChar32(ch); END;
  2134. ch := ch MOD d;
  2135. h2 := (h2*d + ch) MOD q;
  2136. IF backwards THEN
  2137. DEC(i);
  2138. ELSE
  2139. INC(i);
  2140. END;
  2141. IF (h1 = h2) THEN (* verify *)
  2142. IF backwards THEN
  2143. r.SetDirection(1); r.SetPosition(i - patternLength + 1);
  2144. ELSE
  2145. r.SetPosition(i);
  2146. END;
  2147. found := Equals(pattern, r, patternLength, ignoreCase);
  2148. IF backwards THEN r.SetDirection(-1); END;
  2149. END;
  2150. END;
  2151. IF found THEN
  2152. IF backwards THEN RETURN i - patternLength + 1;
  2153. ELSE RETURN i;
  2154. END;
  2155. ELSE RETURN -1;
  2156. END;
  2157. END GenericPos;
  2158. PROCEDURE Replace*(CONST string, by :Texts.UCS32String; text : Texts.Text; VAR nofReplacements : LONGINT);
  2159. VAR pos, stringLen, byLen : LONGINT;
  2160. BEGIN
  2161. ASSERT(text # NIL);
  2162. nofReplacements := 0;
  2163. stringLen := UCS32StrLength(string);
  2164. byLen := UCS32StrLength(by);
  2165. text.AcquireWrite;
  2166. pos := Pos(string, 0, text);
  2167. WHILE (pos > 0) DO
  2168. INC(nofReplacements);
  2169. text.Delete(pos, stringLen);
  2170. text.InsertUCS32(pos, by);
  2171. pos := Pos(string, pos + byLen, text);
  2172. END;
  2173. text.ReleaseWrite;
  2174. END Replace;
  2175. PROCEDURE AddFontFormat*(x : FormatDescriptor);
  2176. BEGIN
  2177. IF x.name # NIL THEN KernelLog.String("name = "); KernelLog.String(x.name^); KernelLog.Ln END;
  2178. IF x.loadProc # NIL THEN KernelLog.String("loadProc = "); KernelLog.String(x.loadProc^); KernelLog.Ln END;
  2179. IF x.storeProc # NIL THEN KernelLog.String("storeProc = "); KernelLog.String(x.storeProc^); KernelLog.Ln END;
  2180. END AddFontFormat;
  2181. PROCEDURE GetConfig;
  2182. VAR sectFM, e : XML.Element;
  2183. p : ANY; enum: XMLObjects.Enumerator;
  2184. f : FormatDescriptor;
  2185. BEGIN
  2186. IF Configuration.config # NIL THEN
  2187. sectFM := Configuration.GetNamedElement(Configuration.config.GetRoot(), "Section", "TextFormats");
  2188. ELSE
  2189. sectFM := NIL;
  2190. END;
  2191. IF sectFM # NIL THEN
  2192. enum := sectFM.GetContents();
  2193. IF enum # NIL THEN
  2194. WHILE enum.HasMoreElements() DO
  2195. p := enum.GetNext();
  2196. IF p IS XML.Element THEN
  2197. NEW(f);
  2198. f.name := p(XML.Element).GetName();
  2199. e := Configuration.GetNamedElement(p(XML.Element), "Setting", "Load");
  2200. IF e # NIL THEN f.loadProc := e.GetAttributeValue("Value") END;
  2201. e := Configuration.GetNamedElement(p(XML.Element), "Setting", "Store");
  2202. IF e # NIL THEN f.storeProc := e.GetAttributeValue("Value") END;
  2203. AddFontFormat(f);
  2204. END
  2205. END
  2206. END;
  2207. END
  2208. END GetConfig;
  2209. (* Oberon File Format *)
  2210. PROCEDURE OberonDecoderFactory*() : Codecs.TextDecoder;
  2211. VAR p : OberonDecoder;
  2212. BEGIN
  2213. NEW(p);
  2214. RETURN p
  2215. END OberonDecoderFactory;
  2216. PROCEDURE OberonEncoderFactory*() : Codecs.TextEncoder;
  2217. VAR p : OberonEncoder;
  2218. BEGIN
  2219. NEW(p);
  2220. RETURN p
  2221. END OberonEncoderFactory;
  2222. (* Bluebottle File Format *)
  2223. PROCEDURE BluebottleDecoderFactory*() : Codecs.TextDecoder;
  2224. VAR p : BluebottleDecoder;
  2225. BEGIN
  2226. NEW(p);
  2227. RETURN p
  2228. END BluebottleDecoderFactory;
  2229. PROCEDURE BluebottleEncoderFactory*() : Codecs.TextEncoder;
  2230. VAR p : BluebottleEncoder;
  2231. BEGIN
  2232. NEW(p);
  2233. RETURN p
  2234. END BluebottleEncoderFactory;
  2235. (* UTF-8 File Format *)
  2236. PROCEDURE UTF8DecoderFactory*() : Codecs.TextDecoder;
  2237. VAR p : UTF8Decoder;
  2238. BEGIN
  2239. NEW(p);
  2240. RETURN p
  2241. END UTF8DecoderFactory;
  2242. PROCEDURE UTF8EncoderFactory*() : Codecs.TextEncoder;
  2243. VAR p : UTF8Encoder;
  2244. BEGIN
  2245. NEW(p);
  2246. RETURN p
  2247. END UTF8EncoderFactory;
  2248. (* ISO8859-1 File Format *)
  2249. PROCEDURE ISO88591DecoderFactory*() : Codecs.TextDecoder;
  2250. VAR p : ISO88591Decoder;
  2251. BEGIN
  2252. NEW(p);
  2253. RETURN p
  2254. END ISO88591DecoderFactory;
  2255. PROCEDURE ISO88591EncoderFactory*() : Codecs.TextEncoder;
  2256. VAR p : ISO88591Encoder;
  2257. BEGIN
  2258. NEW(p);
  2259. RETURN p
  2260. END ISO88591EncoderFactory;
  2261. (* Hex File Format *)
  2262. PROCEDURE HEXDecoderFactory*() : Codecs.TextDecoder;
  2263. VAR p : HEXDecoder;
  2264. BEGIN
  2265. NEW(p);
  2266. RETURN p
  2267. END HEXDecoderFactory;
  2268. PROCEDURE HEXEncoderFactory*() : Codecs.TextEncoder;
  2269. VAR p : HEXEncoder;
  2270. BEGIN
  2271. NEW(p);
  2272. RETURN p
  2273. END HEXEncoderFactory;
  2274. PROCEDURE GetClipboard* (context: Commands.Context);
  2275. VAR r: TextReader;
  2276. BEGIN
  2277. NEW (r, Texts.clipboard);
  2278. Streams.Copy (r, context.out); context.out.Update;
  2279. END GetClipboard;
  2280. PROCEDURE SetClipboard* (context: Commands.Context);
  2281. VAR w: TextWriter;
  2282. BEGIN
  2283. NEW (w, Texts.clipboard);
  2284. Streams.Copy (context.in, w); w.Update;
  2285. END SetClipboard;
  2286. PROCEDURE GetTextReader* (CONST filename: ARRAY OF CHAR): Streams.Reader;
  2287. VAR
  2288. file: Files.File; fileReader: Files.Reader; offset: LONGINT;
  2289. text: Text; format, res: LONGINT; textReader: TextReader;
  2290. BEGIN
  2291. (* Optimisation: skip header of oberon files and return a file reader instead of default text reader*)
  2292. file := Files.Old (filename);
  2293. IF file = NIL THEN RETURN NIL END;
  2294. NEW (fileReader, file, 0);
  2295. IF (fileReader.Get () = 0F0X) & (fileReader.Get () = 001X) THEN
  2296. offset := ORD (fileReader.Get ());
  2297. INC (offset, LONG (ORD (fileReader.Get ())) * 0100H);
  2298. fileReader.SetPos(offset);
  2299. RETURN fileReader
  2300. ELSE
  2301. NEW (text);
  2302. LoadAuto (text, filename, format, res);
  2303. NEW (textReader, text);
  2304. RETURN textReader
  2305. END
  2306. END GetTextReader;
  2307. PROCEDURE GetDefaultAttributes* () : Texts.Attributes;
  2308. VAR
  2309. defaultAttributes : Texts.Attributes;
  2310. font : WMGraphics.Font;
  2311. textColor, textBackColor : LONGINT;
  2312. res : LONGINT;
  2313. BEGIN
  2314. NEW( defaultAttributes );
  2315. Configuration.GetColor( "WindowManager.ColorScheme.Default.TextBackColor", textBackColor, res );
  2316. IF res # Configuration.Ok THEN textBackColor := 0H; END; (* transparent *)
  2317. Configuration.GetColor( "WindowManager.ColorScheme.Default.TextColor", textColor, res );
  2318. IF res # Configuration.Ok THEN textColor := 0FFH; END; (* black *)
  2319. font := WMGraphics.GetDefaultFont( );
  2320. defaultAttributes.Set( textColor, textBackColor, 0, font.name, font.size, font.style );
  2321. RETURN defaultAttributes
  2322. END GetDefaultAttributes;
  2323. BEGIN
  2324. oberonFontAllocatable := NIL;
  2325. GetConfig;
  2326. END TextUtilities.
  2327. TextUtilities.ConvertAll~