scan.c 67 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. scan.c
  5. Abstract:
  6. This module implements scanning strings into various other forms, such as
  7. integers.
  8. Author:
  9. Evan Green 25-May-2013
  10. Environment:
  11. Kernel and User Modes
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include "rtlp.h"
  17. //
  18. // --------------------------------------------------------------------- Macros
  19. //
  20. //
  21. // ---------------------------------------------------------------- Definitions
  22. //
  23. #define INFINITY_STRING "infinity"
  24. #define NAN_STRING "nan"
  25. //
  26. // ------------------------------------------------------ Data Type Definitions
  27. //
  28. //
  29. // ----------------------------------------------- Internal Function Prototypes
  30. //
  31. KSTATUS
  32. RtlpScanInteger (
  33. PSCAN_INPUT Input,
  34. ULONG Base,
  35. ULONG FieldSize,
  36. BOOL Signed,
  37. PLONGLONG Integer,
  38. PULONG CharactersConsumed
  39. );
  40. KSTATUS
  41. RtlpScanDouble (
  42. PSCAN_INPUT Input,
  43. ULONG FieldSize,
  44. double *Double,
  45. PULONG CharactersConsumed
  46. );
  47. VOID
  48. RtlpScannerUnput (
  49. PSCAN_INPUT Input,
  50. CHAR Character
  51. );
  52. VOID
  53. RtlpScannerWideUnput (
  54. PSCAN_INPUT Input,
  55. WCHAR Character
  56. );
  57. BOOL
  58. RtlpScannerGetInput (
  59. PSCAN_INPUT Input,
  60. PCHAR Character
  61. );
  62. BOOL
  63. RtlpScannerGetWideInput (
  64. PSCAN_INPUT Input,
  65. PWCHAR WideCharacter
  66. );
  67. BOOL
  68. RtlpStringScannerGetInput (
  69. PSCAN_INPUT Input,
  70. PCHAR Character
  71. );
  72. //
  73. // -------------------------------------------------------------------- Globals
  74. //
  75. double RtlFirst16PowersOf10[16] = {
  76. 1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8, 1E9, 1E10, 1E11, 1E12, 1E13,
  77. 1E14, 1E15
  78. };
  79. double RtlFirst16NegativePowersOf10[16] = {
  80. 1E0, 1E-1, 1E-2, 1E-3, 1E-4, 1E-5, 1E-6, 1E-7, 1E-8, 1E-9, 1E-10, 1E-11,
  81. 1E-12, 1E-13, 1E-14, 1E-15
  82. };
  83. double RtlPositivePowersOf2[5] = {
  84. 1E16, 1E32, 1E64, 1E128, 1E256
  85. };
  86. double RtlNegativePowersOf2[5] = {
  87. 1E-16, 1E-32, 1E-64, 1E-128, 1E-256
  88. };
  89. //
  90. // ------------------------------------------------------------------ Functions
  91. //
  92. RTL_API
  93. KSTATUS
  94. RtlStringScan (
  95. PSTR Input,
  96. ULONG InputSize,
  97. PSTR Format,
  98. ULONG FormatSize,
  99. CHARACTER_ENCODING Encoding,
  100. PULONG ItemsScanned,
  101. ...
  102. )
  103. /*++
  104. Routine Description:
  105. This routine scans in a string and converts it to a number of arguments
  106. based on a format string.
  107. Arguments:
  108. Input - Supplies a pointer to the input string to scan.
  109. InputSize - Supplies the size of the string in bytes including the null
  110. terminator.
  111. Format - Supplies the format string that specifies how to convert the input
  112. to the arguments.
  113. FormatSize - Supplies the size of the format string in bytes, including
  114. the null terminator.
  115. Encoding - Supplies the character encoding to use when scanning into
  116. wide strings or characters.
  117. ItemsScanned - Supplies a pointer where the number of items scanned will
  118. be returned (not counting any %n specifiers).
  119. ... - Supplies the remaining pointer arguments where the scanned data will
  120. be returned.
  121. Return Value:
  122. STATUS_SUCCESS if the input was successfully scanned according to the
  123. format.
  124. STATUS_INVALID_SEQUENCE if the input did not match the format or the
  125. format was invalid.
  126. STATUS_ARGUMENT_EXPECTED if not enough arguments were supplied for the
  127. format.
  128. STATUS_END_OF_FILE if the input ended before any arguments were converted
  129. or any matching failures occurred.
  130. --*/
  131. {
  132. va_list ArgumentList;
  133. KSTATUS Status;
  134. va_start(ArgumentList, ItemsScanned);
  135. Status = RtlStringScanVaList(Input,
  136. InputSize,
  137. Format,
  138. FormatSize,
  139. Encoding,
  140. ItemsScanned,
  141. ArgumentList);
  142. va_end(ArgumentList);
  143. return Status;
  144. }
  145. RTL_API
  146. KSTATUS
  147. RtlStringScanVaList (
  148. PSTR Input,
  149. ULONG InputSize,
  150. PSTR Format,
  151. ULONG FormatSize,
  152. CHARACTER_ENCODING Encoding,
  153. PULONG ItemsScanned,
  154. va_list Arguments
  155. )
  156. /*++
  157. Routine Description:
  158. This routine scans in a string and converts it to a number of arguments
  159. based on a format string.
  160. Arguments:
  161. Input - Supplies a pointer to the input string to scan.
  162. InputSize - Supplies the size of the string in bytes including the null
  163. terminator.
  164. Format - Supplies the format string that specifies how to convert the input
  165. to the arguments.
  166. FormatSize - Supplies the size of the format string in bytes, including
  167. the null terminator.
  168. Encoding - Supplies the character encoding to use when scanning into
  169. wide strings or characters.
  170. ItemsScanned - Supplies a pointer where the number of items scanned will
  171. be returned (not counting any %n specifiers).
  172. Arguments - Supplies the initialized arguments list where various pieces
  173. of the formatted string will be returned.
  174. Return Value:
  175. STATUS_SUCCESS if the input was successfully scanned according to the
  176. format.
  177. STATUS_INVALID_SEQUENCE if the input did not match the format or the
  178. format was invalid.
  179. STATUS_ARGUMENT_EXPECTED if not enough arguments were supplied for the
  180. format.
  181. STATUS_END_OF_FILE if the input ended before any arguments were converted
  182. or any matching failures occurred.
  183. --*/
  184. {
  185. SCAN_INPUT InputParameters;
  186. KSTATUS Status;
  187. if (Input == NULL) {
  188. return STATUS_INVALID_PARAMETER;
  189. }
  190. InputParameters.ReadU.GetInput = RtlpStringScannerGetInput;
  191. InputParameters.DataU.String = Input;
  192. InputParameters.StringSize = InputSize;
  193. InputParameters.ValidUnputCharacters = 0;
  194. InputParameters.CharactersRead = 0;
  195. RtlInitializeMultibyteState(&(InputParameters.State), Encoding);
  196. Status = RtlScan(&InputParameters,
  197. Format,
  198. FormatSize,
  199. ItemsScanned,
  200. Arguments);
  201. return Status;
  202. }
  203. RTL_API
  204. KSTATUS
  205. RtlStringScanInteger (
  206. PSTR *String,
  207. PULONG StringSize,
  208. ULONG Base,
  209. BOOL Signed,
  210. PLONGLONG Integer
  211. )
  212. /*++
  213. Routine Description:
  214. This routine converts a string into an integer. It scans past leading
  215. whitespace.
  216. Arguments:
  217. String - Supplies a pointer that on input contains a pointer to the string
  218. to scan. On output, the string advanced past the scanned value (if any)
  219. will be returned. If the entire string is whitespace or starts with an
  220. invalid character, this parameter will not be modified.
  221. StringSize - Supplies a pointer that on input contains the size of the
  222. string, in bytes, including the null terminator. On output, this will
  223. contain the size of the string minus the number of bytes scanned by
  224. this routine. Said differently, it will return the size of the output
  225. to the string parameter in bytes including the null terminator.
  226. Base - Supplies the base of the integer to scan. Valid values are zero and
  227. two through thirty six. If zero is supplied, this routine will attempt
  228. to automatically detect what the base is out of bases 8, 10, and 16.
  229. Signed - Supplies a boolean indicating whether the integer to scan is
  230. signed or not.
  231. Integer - Supplies a pointer where the resulting integer is returned on
  232. success.
  233. Return Value:
  234. STATUS_SUCCESS if an integer was successfully scanned.
  235. STATUS_INVALID_SEQUENCE if a valid integer could not be scanned.
  236. STATUS_INTEGER_OVERFLOW if the result overflowed. In this case the integer
  237. returned will be MAX_LONGLONG, MIN_LONGLONG, or MAX_ULONGLONG depending on
  238. the signedness and value.
  239. STATUS_END_OF_FILE if the input ended before the value was converted
  240. or a matching failure occurred.
  241. --*/
  242. {
  243. ULONG CharactersConsumed;
  244. SCAN_INPUT Input;
  245. KSTATUS Status;
  246. if (String == NULL) {
  247. return STATUS_INVALID_PARAMETER;
  248. }
  249. Input.ReadU.GetInput = RtlpStringScannerGetInput;
  250. Input.DataU.String = *String;
  251. Input.StringSize = *StringSize;
  252. Input.ValidUnputCharacters = 0;
  253. Input.CharactersRead = 0;
  254. RtlInitializeMultibyteState(&(Input.State), CharacterEncodingDefault);
  255. Status = RtlpScanInteger(&Input,
  256. Base,
  257. *StringSize,
  258. Signed,
  259. Integer,
  260. &CharactersConsumed);
  261. *StringSize -= CharactersConsumed;
  262. *String += CharactersConsumed;
  263. return Status;
  264. }
  265. RTL_API
  266. KSTATUS
  267. RtlStringScanDouble (
  268. PSTR *String,
  269. PULONG StringSize,
  270. double *Double
  271. )
  272. /*++
  273. Routine Description:
  274. This routine converts a string into a floating point double. It scans past
  275. leading whitespace.
  276. Arguments:
  277. String - Supplies a pointer that on input contains a pointer to the string
  278. to scan. On output, the string advanced past the scanned value (if any)
  279. will be returned. If the entire string is whitespace or starts with an
  280. invalid character, this parameter will not be modified.
  281. StringSize - Supplies a pointer that on input contains the size of the
  282. string, in bytes, including the null terminator. On output, this will
  283. contain the size of the string minus the number of bytes scanned by
  284. this routine. Said differently, it will return the size of the output
  285. to the string parameter in bytes including the null terminator.
  286. Double - Supplies a pointer where the resulting double is returned on
  287. success.
  288. Return Value:
  289. STATUS_SUCCESS if an integer was successfully scanned.
  290. STATUS_INVALID_SEQUENCE if a valid double could not be scanned.
  291. STATUS_OUT_OF_BOUNDS if the exponent was out of range.
  292. STATUS_END_OF_FILE if the input ended before the value was converted
  293. or a matching failure occurred.
  294. --*/
  295. {
  296. ULONG CharactersConsumed;
  297. SCAN_INPUT Input;
  298. KSTATUS Status;
  299. if (String == NULL) {
  300. return STATUS_INVALID_PARAMETER;
  301. }
  302. Input.ReadU.GetInput = RtlpStringScannerGetInput;
  303. Input.DataU.String = *String;
  304. Input.StringSize = *StringSize;
  305. Input.ValidUnputCharacters = 0;
  306. Input.CharactersRead = 0;
  307. RtlInitializeMultibyteState(&(Input.State), CharacterEncodingDefault);
  308. Status = RtlpScanDouble(&Input, *StringSize, Double, &CharactersConsumed);
  309. *StringSize -= CharactersConsumed;
  310. *String += CharactersConsumed;
  311. return Status;
  312. }
  313. RTL_API
  314. KSTATUS
  315. RtlScan (
  316. PSCAN_INPUT Input,
  317. PSTR Format,
  318. ULONG FormatLength,
  319. PULONG ItemsScanned,
  320. va_list ArgumentList
  321. )
  322. /*++
  323. Routine Description:
  324. This routine scans from an input and converts the input to various
  325. parameters according to a specified format.
  326. Arguments:
  327. Input - Supplies a pointer to the filled out scan input structure which
  328. will be used to retrieve more input.
  329. Format - Supplies the format string which specifies how to convert the
  330. input to the argument list.
  331. FormatLength - Supplies the size of the format length string in bytes,
  332. including the null terminator.
  333. ItemsScanned - Supplies a pointer where the number of parameters filled in
  334. (not counting %n) will be returned.
  335. ArgumentList - Supplies the list of arguments that will get filled out
  336. based on the input and format string.
  337. Return Value:
  338. STATUS_SUCCESS if the input was successfully scanned according to the
  339. format.
  340. STATUS_INVALID_SEQUENCE if the input did not match the format or the
  341. format was invalid.
  342. STATUS_ARGUMENT_EXPECTED if not enough arguments were supplied for the
  343. format.
  344. STATUS_END_OF_FILE if the input ended before any arguments were converted
  345. or any matching failures occurred.
  346. --*/
  347. {
  348. BOOL AdvanceFormat;
  349. PCHAR Argument;
  350. ULONG ArgumentsWritten;
  351. BOOL AssignmentSuppression;
  352. ULONG Base;
  353. CHAR Character;
  354. ULONG CharactersConsumed;
  355. double Double;
  356. ULONG FieldWidth;
  357. CHAR InputCharacter;
  358. BOOL InScanSet;
  359. LONGLONG Integer;
  360. ULONG LengthModifier;
  361. BOOL LongSpecified;
  362. ULONG Position;
  363. BOOL Result;
  364. PSTR ScanSetBegin;
  365. BOOL ScanSetGotSomething;
  366. ULONG ScanSetIndex;
  367. ULONG ScanSetLength;
  368. BOOL ScanSetNegated;
  369. KSTATUS ScanStatus;
  370. BOOL Signed;
  371. KSTATUS Status;
  372. WCHAR WideCharacter;
  373. PWSTR WideStringArgument;
  374. ASSERT(RtlIsCharacterEncodingSupported(Input->State.Encoding) != FALSE);
  375. ArgumentsWritten = 0;
  376. *ItemsScanned = 0;
  377. Result = FALSE;
  378. //
  379. // Loop getting characters.
  380. //
  381. while (FormatLength != 0) {
  382. AssignmentSuppression = FALSE;
  383. FieldWidth = -1;
  384. LengthModifier = 0;
  385. Position = -1;
  386. Character = *Format;
  387. //
  388. // Any whitespace in the format blasts through all whitespace in the
  389. // input.
  390. //
  391. if (RtlIsCharacterSpace(Character) != FALSE) {
  392. do {
  393. Result = RtlpScannerGetInput(Input, &InputCharacter);
  394. if (Result == FALSE) {
  395. break;
  396. }
  397. } while (RtlIsCharacterSpace(InputCharacter) != FALSE);
  398. //
  399. // This went one too far, put the non-whitespace character back.
  400. //
  401. if (Result != FALSE) {
  402. RtlpScannerUnput(Input, InputCharacter);
  403. }
  404. //
  405. // If it's a terminator, stop scanning.
  406. //
  407. } else if (Character == '\0') {
  408. break;
  409. //
  410. // If it's not a percent, then it's just a regular character, match it
  411. // up.
  412. //
  413. } else if (Character != '%') {
  414. Result = RtlpScannerGetInput(Input, &InputCharacter);
  415. if (Result == FALSE) {
  416. Status = STATUS_END_OF_FILE;
  417. goto ScanEnd;
  418. }
  419. if (InputCharacter != Character) {
  420. Status = STATUS_INVALID_SEQUENCE;
  421. goto ScanEnd;
  422. }
  423. //
  424. // Big boy land, it's a format specifier (percent sign).
  425. //
  426. } else {
  427. ASSERT(Character == '%');
  428. Format += 1;
  429. FormatLength -= 1;
  430. if ((FormatLength == 0) || (*Format == '\0')) {
  431. Status = STATUS_INVALID_SEQUENCE;
  432. goto ScanEnd;
  433. }
  434. Character = *Format;
  435. //
  436. // Potentially get a positional argument (or field length, it's
  437. // unclear yet).
  438. //
  439. if ((Character >= '0') && (Character <= '9')) {
  440. ScanStatus = RtlStringScanInteger(&Format,
  441. &FormatLength,
  442. 10,
  443. FALSE,
  444. &Integer);
  445. if (!KSUCCESS(ScanStatus)) {
  446. Status = ScanStatus;
  447. goto ScanEnd;
  448. }
  449. if ((FormatLength == 0) || (*Format == '\0')) {
  450. Status = STATUS_END_OF_FILE;
  451. goto ScanEnd;
  452. }
  453. if (Integer <= 0) {
  454. Status = STATUS_INVALID_SEQUENCE;
  455. goto ScanEnd;
  456. }
  457. //
  458. // A dollar sign means it was a positional argument, none means
  459. // it was a field width.
  460. //
  461. Character = *Format;
  462. if (Character == '$') {
  463. Position = (ULONG)Integer;
  464. Format += 1;
  465. FormatLength -= 1;
  466. if (FormatLength == 0) {
  467. Status = STATUS_INVALID_SEQUENCE;
  468. goto ScanEnd;
  469. }
  470. Character = *Format;
  471. if (Character == '\0') {
  472. Status = STATUS_INVALID_SEQUENCE;
  473. goto ScanEnd;
  474. }
  475. } else {
  476. FieldWidth = (ULONG)Integer;
  477. }
  478. }
  479. //
  480. // Watch out for assignment suppression.
  481. //
  482. if (Character == '*') {
  483. AssignmentSuppression = TRUE;
  484. Format += 1;
  485. FormatLength -= 1;
  486. if (FormatLength == 0) {
  487. Status = STATUS_INVALID_SEQUENCE;
  488. goto ScanEnd;
  489. }
  490. Character = *Format;
  491. }
  492. //
  493. // If not already found, try again to scan a field width, as it
  494. // could have been after the asterisk.
  495. //
  496. if ((FieldWidth == -1) &&
  497. (Character >= '0') && (Character <= '9')) {
  498. ScanStatus = RtlStringScanInteger(&Format,
  499. &FormatLength,
  500. 10,
  501. FALSE,
  502. &Integer);
  503. if (!KSUCCESS(ScanStatus)) {
  504. Status = ScanStatus;
  505. goto ScanEnd;
  506. }
  507. if ((FormatLength == 0) || (*Format == '\0')) {
  508. Status = STATUS_END_OF_FILE;
  509. goto ScanEnd;
  510. }
  511. if (Integer <= 0) {
  512. Status = STATUS_INVALID_SEQUENCE;
  513. goto ScanEnd;
  514. }
  515. FieldWidth = (ULONG)Integer;
  516. Character = *Format;
  517. }
  518. //
  519. // Look for a length modifier. There are two-character wide
  520. // length modifiers hh for char and ll for long long.
  521. //
  522. AdvanceFormat = FALSE;
  523. LongSpecified = FALSE;
  524. //
  525. // If the character is 'h', then the parameter points to a short.
  526. // Advance manually here to look for 'hh' as well, which makes the
  527. // parameter a char.
  528. //
  529. if (Character == 'h') {
  530. LengthModifier = sizeof(SHORT);
  531. Format += 1;
  532. FormatLength -= 1;
  533. if ((FormatLength == 0) || (*Format == '\0')) {
  534. Status = STATUS_INVALID_SEQUENCE;
  535. goto ScanEnd;
  536. }
  537. Character = *Format;
  538. if (Character == 'h') {
  539. LengthModifier = sizeof(CHAR);
  540. AdvanceFormat = TRUE;
  541. }
  542. //
  543. // If the character is 'l', then the parameter points to a long.
  544. // Advance manually here as well to look for the 'll', which is
  545. // long long.
  546. //
  547. } else if (Character == 'l') {
  548. LongSpecified = TRUE;
  549. LengthModifier = sizeof(LONG);
  550. Format += 1;
  551. FormatLength -= 1;
  552. if ((FormatLength == 0) || (*Format == '\0')) {
  553. Status = STATUS_INVALID_SEQUENCE;
  554. goto ScanEnd;
  555. }
  556. Character = *Format;
  557. if (Character == 'l') {
  558. LongSpecified = FALSE;
  559. LengthModifier = sizeof(LONGLONG);
  560. AdvanceFormat = TRUE;
  561. }
  562. //
  563. // The 'j' override specifies an intmax_t type.
  564. //
  565. } else if (Character == 'j') {
  566. LengthModifier = sizeof(intmax_t);
  567. AdvanceFormat = TRUE;
  568. //
  569. // The 'z' override specifies a size_t type.
  570. //
  571. } else if (Character == 'z') {
  572. LengthModifier = sizeof(size_t);
  573. AdvanceFormat = TRUE;
  574. //
  575. // The 't' override specifies a ptrdiff_t type.
  576. //
  577. } else if (Character == 't') {
  578. LengthModifier = sizeof(ptrdiff_t);
  579. AdvanceFormat = TRUE;
  580. //
  581. // The 'L' override specifies a long double.
  582. //
  583. } else if (Character == 'L') {
  584. LengthModifier = sizeof(LONGLONG);
  585. AdvanceFormat = TRUE;
  586. }
  587. if (AdvanceFormat != FALSE) {
  588. Format += 1;
  589. FormatLength -= 1;
  590. if ((FormatLength == 0) || (*Format == '\0')) {
  591. Status = STATUS_INVALID_SEQUENCE;
  592. goto ScanEnd;
  593. }
  594. Character = *Format;
  595. }
  596. //
  597. // Get the argument unless the assignment is suppressed.
  598. //
  599. Argument = NULL;
  600. if ((AssignmentSuppression == FALSE) && (Character != '%')) {
  601. //
  602. // TODO: Handle positional arguments. Not sure how to do
  603. // that with just va_arg. If they're all pointer types
  604. // perhaps pointer arithmetic is fine if there were a way
  605. // to get the original address of the first argument.
  606. //
  607. if (Position != -1) {
  608. ASSERT(FALSE);
  609. Argument = NULL;
  610. } else {
  611. Argument = va_arg(ArgumentList, PCHAR);
  612. }
  613. if (Argument == NULL) {
  614. Status = STATUS_ARGUMENT_EXPECTED;
  615. goto ScanEnd;
  616. }
  617. }
  618. //
  619. // Convert an lc to a C and and ls to an S just to make the if
  620. // statements easier.
  621. //
  622. if (LongSpecified != FALSE) {
  623. if (Character == 'c') {
  624. Character = 'C';
  625. } else if (Character == 's') {
  626. Character = 'S';
  627. }
  628. }
  629. //
  630. // All the wiggly stuff is out of the way, get down to the real
  631. // format specifier. First check for an integer.
  632. //
  633. if ((Character == 'd') || (Character == 'i') ||
  634. (Character == 'o') || (Character == 'u') ||
  635. (Character == 'x') || (Character == 'X')) {
  636. if (LengthModifier == 0) {
  637. LengthModifier = sizeof(INT);
  638. }
  639. Signed = TRUE;
  640. if (Character == 'd') {
  641. Base = 10;
  642. } else if (Character == 'i') {
  643. Base = 0;
  644. } else if (Character == 'o') {
  645. Base = 8;
  646. } else if (Character == 'u') {
  647. Base = 10;
  648. Signed = FALSE;
  649. } else {
  650. Base = 16;
  651. }
  652. ScanStatus = RtlpScanInteger(Input,
  653. Base,
  654. FieldWidth,
  655. Signed,
  656. &Integer,
  657. &CharactersConsumed);
  658. if (!KSUCCESS(ScanStatus)) {
  659. Status = ScanStatus;
  660. goto ScanEnd;
  661. }
  662. if (AssignmentSuppression == FALSE) {
  663. //
  664. // Write the argument.
  665. //
  666. switch (LengthModifier) {
  667. case sizeof(CHAR):
  668. *((PCHAR)Argument) = (CHAR)Integer;
  669. break;
  670. case sizeof(SHORT):
  671. *((PSHORT)Argument) = (SHORT)Integer;
  672. break;
  673. case sizeof(LONG):
  674. *((PLONG)Argument) = (LONG)Integer;
  675. break;
  676. case sizeof(LONGLONG):
  677. *((PLONGLONG)Argument) = (LONGLONG)Integer;
  678. break;
  679. default:
  680. ASSERT(FALSE);
  681. Status = STATUS_INVALID_SEQUENCE;
  682. goto ScanEnd;
  683. }
  684. ArgumentsWritten += 1;
  685. }
  686. //
  687. // Handle floats.
  688. //
  689. } else if ((Character == 'a') || (Character == 'A') ||
  690. (Character == 'e') || (Character == 'E') ||
  691. (Character == 'f') || (Character == 'F') ||
  692. (Character == 'g') || (Character == 'G')) {
  693. ScanStatus = RtlpScanDouble(Input,
  694. FieldWidth,
  695. &Double,
  696. &CharactersConsumed);
  697. if (!KSUCCESS(ScanStatus)) {
  698. Status = ScanStatus;
  699. goto ScanEnd;
  700. }
  701. if (AssignmentSuppression == FALSE) {
  702. switch (LengthModifier) {
  703. case sizeof(LONG):
  704. *((double *)Argument) = Double;
  705. break;
  706. case sizeof(LONGLONG):
  707. *((long double *)Argument) = Double;
  708. break;
  709. default:
  710. *((float *)Argument) = (float)Double;
  711. break;
  712. }
  713. ArgumentsWritten += 1;
  714. }
  715. //
  716. // Handle string copies.
  717. //
  718. } else if (Character == 's') {
  719. //
  720. // First get past any whitespace.
  721. //
  722. do {
  723. Result = RtlpScannerGetInput(Input, &InputCharacter);
  724. if ((Result == FALSE) || (InputCharacter == '\0')) {
  725. Status = STATUS_END_OF_FILE;
  726. goto ScanEnd;
  727. }
  728. } while (RtlIsCharacterSpace(InputCharacter) != FALSE);
  729. //
  730. // Now loop putting non-whitespace characters into the
  731. // argument. Note how the destination argument buffer is
  732. // unbounded? Very dangerous to use without a field width.
  733. //
  734. do {
  735. if (AssignmentSuppression == FALSE) {
  736. *Argument = InputCharacter;
  737. }
  738. Argument += 1;
  739. FieldWidth -= 1;
  740. Result = RtlpScannerGetInput(Input, &InputCharacter);
  741. if ((Result == FALSE) || (InputCharacter == '\0')) {
  742. Status = STATUS_END_OF_FILE;
  743. break;
  744. }
  745. } while ((FieldWidth != 0) &&
  746. (RtlIsCharacterSpace(InputCharacter) == FALSE));
  747. //
  748. // Put the last character back.
  749. //
  750. if (Result != FALSE) {
  751. RtlpScannerUnput(Input, InputCharacter);
  752. }
  753. //
  754. // Null terminate the destination string.
  755. //
  756. if (AssignmentSuppression == FALSE) {
  757. *Argument = '\0';
  758. ArgumentsWritten += 1;
  759. }
  760. //
  761. // Handle wide string copies.
  762. //
  763. } else if (Character == 'S') {
  764. RtlResetMultibyteState(&(Input->State));
  765. //
  766. // First get past any whitespace.
  767. //
  768. do {
  769. Result = RtlpScannerGetWideInput(Input, &WideCharacter);
  770. if ((Result == FALSE) || (InputCharacter == L'\0')) {
  771. Status = STATUS_END_OF_FILE;
  772. goto ScanEnd;
  773. }
  774. } while (RtlIsCharacterSpaceWide(WideCharacter) != FALSE);
  775. //
  776. // Now loop putting non-whitespace characters into the
  777. // argument. Note how the destination argument buffer is
  778. // unbounded? Very dangerous to use without a field width.
  779. //
  780. WideStringArgument = (PWSTR)Argument;
  781. do {
  782. if (AssignmentSuppression == FALSE) {
  783. *WideStringArgument = WideCharacter;
  784. }
  785. WideStringArgument += 1;
  786. FieldWidth -= 1;
  787. Result = RtlpScannerGetWideInput(Input, &WideCharacter);
  788. if ((Result == FALSE) || (WideCharacter == L'\0')) {
  789. Status = STATUS_END_OF_FILE;
  790. break;
  791. }
  792. } while ((FieldWidth != 0) &&
  793. (RtlIsCharacterSpaceWide(WideCharacter) == FALSE));
  794. //
  795. // Put the last character back.
  796. //
  797. if (Result != FALSE) {
  798. RtlpScannerWideUnput(Input, WideCharacter);
  799. }
  800. //
  801. // Null terminate the destination string.
  802. //
  803. if (AssignmentSuppression == FALSE) {
  804. *WideStringArgument = L'\0';
  805. ArgumentsWritten += 1;
  806. }
  807. //
  808. // Handle a character (or a bunch of them).
  809. //
  810. } else if (Character == 'c') {
  811. if (FieldWidth == -1) {
  812. FieldWidth = 1;
  813. }
  814. Result = RtlpScannerGetInput(Input, &InputCharacter);
  815. if ((Result == FALSE) || (InputCharacter == '\0')) {
  816. Status = STATUS_END_OF_FILE;
  817. goto ScanEnd;
  818. }
  819. while (TRUE) {
  820. if (AssignmentSuppression == FALSE) {
  821. *Argument = InputCharacter;
  822. }
  823. Argument += 1;
  824. FieldWidth -= 1;
  825. if (FieldWidth == 0) {
  826. break;
  827. }
  828. Result = RtlpScannerGetInput(Input, &InputCharacter);
  829. if ((Result == FALSE) || (InputCharacter == '\0')) {
  830. Status = STATUS_END_OF_FILE;
  831. break;
  832. }
  833. }
  834. if (AssignmentSuppression == FALSE) {
  835. ArgumentsWritten += 1;
  836. }
  837. //
  838. // Handle a wide character (or a bunch of them).
  839. //
  840. } else if (Character == 'C') {
  841. RtlResetMultibyteState(&(Input->State));
  842. if (FieldWidth == -1) {
  843. FieldWidth = 1;
  844. }
  845. Result = RtlpScannerGetWideInput(Input, &WideCharacter);
  846. if ((Result == FALSE) || (WideCharacter == L'\0')) {
  847. Status = STATUS_END_OF_FILE;
  848. goto ScanEnd;
  849. }
  850. WideStringArgument = (PWSTR)Argument;
  851. while (TRUE) {
  852. if (AssignmentSuppression == FALSE) {
  853. *WideStringArgument = WideCharacter;
  854. }
  855. WideStringArgument += 1;
  856. FieldWidth -= 1;
  857. if (FieldWidth == 0) {
  858. break;
  859. }
  860. Result = RtlpScannerGetWideInput(Input, &WideCharacter);
  861. if ((Result == FALSE) || (WideCharacter == '\0')) {
  862. Status = STATUS_END_OF_FILE;
  863. break;
  864. }
  865. }
  866. if (AssignmentSuppression == FALSE) {
  867. ArgumentsWritten += 1;
  868. }
  869. //
  870. // Handle a scanset.
  871. //
  872. } else if (Character == '[') {
  873. Format += 1;
  874. FormatLength -= 1;
  875. if (FormatLength == 0) {
  876. Status = STATUS_INVALID_SEQUENCE;
  877. goto ScanEnd;
  878. }
  879. //
  880. // The circumflex (^) negates the scanset.
  881. //
  882. ScanSetNegated = FALSE;
  883. if (*Format == '^') {
  884. ScanSetNegated = TRUE;
  885. Format += 1;
  886. FormatLength -= 1;
  887. if (FormatLength == 0) {
  888. break;
  889. }
  890. }
  891. //
  892. // Find the end of the scanset. If the scanset starts with
  893. // [] or [^] then the left bracket is considered to be part of
  894. // the scanset. Annoyingly, there is no way to specify a
  895. // sequence of just ^, which seems like a glaring hole to this
  896. // programmer.
  897. //
  898. ScanSetBegin = Format;
  899. ScanSetLength = 0;
  900. while ((FormatLength != 0) && (*Format != '\0')) {
  901. if ((*Format == ']') && (ScanSetLength != 0)) {
  902. break;
  903. }
  904. ScanSetLength += 1;
  905. Format += 1;
  906. FormatLength -= 1;
  907. }
  908. if ((FormatLength == 0) || (*Format == '\0')) {
  909. Status = STATUS_INVALID_SEQUENCE;
  910. goto ScanEnd;
  911. }
  912. //
  913. // Now grab characters that are either in the scanset or not in
  914. // the scanset.
  915. //
  916. ScanSetGotSomething = FALSE;
  917. if (LongSpecified != FALSE) {
  918. WideStringArgument = (PWSTR)Argument;
  919. do {
  920. Result = RtlpScannerGetWideInput(Input, &WideCharacter);
  921. if ((Result == FALSE) || (WideCharacter == L'\0')) {
  922. break;
  923. }
  924. InScanSet = FALSE;
  925. for (ScanSetIndex = 0;
  926. ScanSetIndex < ScanSetLength;
  927. ScanSetIndex += 1) {
  928. if (WideCharacter == ScanSetBegin[ScanSetIndex]) {
  929. InScanSet = TRUE;
  930. break;
  931. }
  932. }
  933. //
  934. // Break out if it's not negated and it's not in the
  935. // scanset, or it is negated and it is in the scanset.
  936. // Write it out the long way and the simplification will
  937. // be more obvious.
  938. //
  939. if (ScanSetNegated == InScanSet) {
  940. break;
  941. }
  942. if (AssignmentSuppression == FALSE) {
  943. *WideStringArgument = WideCharacter;
  944. WideStringArgument += 1;
  945. }
  946. FieldWidth -= 1;
  947. ScanSetGotSomething = TRUE;
  948. } while (FieldWidth != 0);
  949. if (ScanSetGotSomething == FALSE) {
  950. Status = STATUS_INVALID_SEQUENCE;
  951. goto ScanEnd;
  952. }
  953. //
  954. // Put the last character back.
  955. //
  956. if ((Result != FALSE) && (FieldWidth != 0)) {
  957. RtlpScannerWideUnput(Input, WideCharacter);
  958. }
  959. //
  960. // Null terminate the destination string.
  961. //
  962. if (AssignmentSuppression == FALSE) {
  963. *WideStringArgument = L'\0';
  964. ArgumentsWritten += 1;
  965. }
  966. //
  967. // Long was not specified, these are just normal bytes in the
  968. // input.
  969. //
  970. } else {
  971. do {
  972. Result = RtlpScannerGetInput(Input, &InputCharacter);
  973. if ((Result == FALSE) || (InputCharacter == '\0')) {
  974. break;
  975. }
  976. InScanSet = FALSE;
  977. for (ScanSetIndex = 0;
  978. ScanSetIndex < ScanSetLength;
  979. ScanSetIndex += 1) {
  980. if (InputCharacter == ScanSetBegin[ScanSetIndex]) {
  981. InScanSet = TRUE;
  982. break;
  983. }
  984. }
  985. //
  986. // Break out if it's not negated and it's not in the
  987. // scanset, or it is negated and it is in the scanset.
  988. // Write it out the long way and the simplification will
  989. // be more obvious.
  990. //
  991. if (ScanSetNegated == InScanSet) {
  992. break;
  993. }
  994. if (AssignmentSuppression == FALSE) {
  995. *Argument = InputCharacter;
  996. Argument += 1;
  997. }
  998. FieldWidth -= 1;
  999. ScanSetGotSomething = TRUE;
  1000. } while (FieldWidth != 0);
  1001. if (ScanSetGotSomething == FALSE) {
  1002. Status = STATUS_INVALID_SEQUENCE;
  1003. goto ScanEnd;
  1004. }
  1005. //
  1006. // Put the last character back.
  1007. //
  1008. if ((Result != FALSE) && (FieldWidth != 0)) {
  1009. RtlpScannerUnput(Input, InputCharacter);
  1010. }
  1011. //
  1012. // Null terminate the destination string.
  1013. //
  1014. if (AssignmentSuppression == FALSE) {
  1015. *Argument = '\0';
  1016. ArgumentsWritten += 1;
  1017. }
  1018. }
  1019. //
  1020. // Handle a little old percent. Double percents are just the
  1021. // percent sign literal.
  1022. //
  1023. } else if (Character == '%') {
  1024. Result = RtlpScannerGetInput(Input, &InputCharacter);
  1025. if (Result == FALSE) {
  1026. Status = STATUS_END_OF_FILE;
  1027. goto ScanEnd;
  1028. }
  1029. if (InputCharacter != Character) {
  1030. Status = STATUS_INVALID_SEQUENCE;
  1031. goto ScanEnd;
  1032. }
  1033. //
  1034. // Return the number of bytes read from the input to get to this
  1035. // point. This doesn't count in the number of arguments written.
  1036. //
  1037. } else if (Character == 'n') {
  1038. if (AssignmentSuppression == FALSE) {
  1039. *((PINT)Argument) = Input->CharactersRead -
  1040. Input->ValidUnputCharacters;
  1041. }
  1042. //
  1043. // This is an unknown format specifier.
  1044. //
  1045. } else {
  1046. Status = STATUS_NOT_SUPPORTED;
  1047. goto ScanEnd;
  1048. }
  1049. }
  1050. //
  1051. // Advance to the next character in the format string.
  1052. //
  1053. Format += 1;
  1054. FormatLength -= 1;
  1055. }
  1056. Status = STATUS_SUCCESS;
  1057. ScanEnd:
  1058. if ((Status == STATUS_INVALID_SEQUENCE) && (Result != FALSE)) {
  1059. RtlpScannerUnput(Input, InputCharacter);
  1060. }
  1061. if ((Status == STATUS_END_OF_FILE) && (ArgumentsWritten != 0)) {
  1062. Status = STATUS_SUCCESS;
  1063. }
  1064. *ItemsScanned = ArgumentsWritten;
  1065. return Status;
  1066. }
  1067. //
  1068. // --------------------------------------------------------- Internal Functions
  1069. //
  1070. KSTATUS
  1071. RtlpScanInteger (
  1072. PSCAN_INPUT Input,
  1073. ULONG Base,
  1074. ULONG FieldSize,
  1075. BOOL Signed,
  1076. PLONGLONG Integer,
  1077. PULONG CharactersConsumed
  1078. )
  1079. /*++
  1080. Routine Description:
  1081. This routine converts a string into an integer. It scans past leading
  1082. whitespace.
  1083. Arguments:
  1084. Input - Supplies a pointer to the filled out scan input structure which
  1085. will be used to retrieve more input.
  1086. Base - Supplies the base of the integer to scan. Valid values are zero and
  1087. two through thirty six. If zero is supplied, this routine will attempt
  1088. to automatically detect what the base is out of bases 8, 10, and 16.
  1089. Signed - Supplies a boolean indicating if the integer is signed or not.
  1090. FieldSize - Supplies the maximum number of characters to scan for the
  1091. integer.
  1092. Integer - Supplies a pointer where the resulting integer is returned on
  1093. success.
  1094. CharactersConsumed - Supplies a pointer where the number characters consumed
  1095. will be stored.
  1096. Return Value:
  1097. STATUS_SUCCESS if an integer was successfully scanned.
  1098. STATUS_INVALID_SEQUENCE if a valid integer could not be scanned.
  1099. STATUS_INTEGER_OVERFLOW if the result overflowed. In this case the integer
  1100. returned will be MAX_LONGLONG, MIN_LONGLONG, or MAX_ULONGLONG depending on
  1101. the signedness and value.
  1102. STATUS_END_OF_FILE if the end of the file was reached before any
  1103. non-whitespace could be retrieved.
  1104. --*/
  1105. {
  1106. CHAR Character;
  1107. ULONG CharacterCount;
  1108. CHAR MaxDigit;
  1109. CHAR MaxLetter;
  1110. BOOL Negative;
  1111. ULONGLONG NewValue;
  1112. BOOL Result;
  1113. KSTATUS Status;
  1114. BOOL ValidCharacterFound;
  1115. ULONGLONG Value;
  1116. *CharactersConsumed = 0;
  1117. CharacterCount = 0;
  1118. *Integer = 0;
  1119. Negative = FALSE;
  1120. Result = RtlpScannerGetInput(Input, &Character);
  1121. if ((Result == FALSE) || (Character == '\0')) {
  1122. return STATUS_END_OF_FILE;
  1123. }
  1124. //
  1125. // Scan past any whitespace.
  1126. //
  1127. while (RtlIsCharacterSpace(Character) != FALSE) {
  1128. CharacterCount += 1;
  1129. Result = RtlpScannerGetInput(Input, &Character);
  1130. if ((Result == FALSE) || (Character == '\0')) {
  1131. return STATUS_END_OF_FILE;
  1132. }
  1133. }
  1134. //
  1135. // Get past any optional plus or minus.
  1136. //
  1137. if ((Character == '+') || (Character == '-')) {
  1138. if (Character == '-') {
  1139. Negative = TRUE;
  1140. }
  1141. if (FieldSize == 0) {
  1142. Status = STATUS_INVALID_SEQUENCE;
  1143. goto ScanIntegerEnd;
  1144. }
  1145. CharacterCount += 1;
  1146. FieldSize -= 1;
  1147. Result = RtlpScannerGetInput(Input, &Character);
  1148. if ((Result == FALSE) || (Character == '\0') || (FieldSize == 0)) {
  1149. Status = STATUS_INVALID_SEQUENCE;
  1150. goto ScanIntegerEnd;
  1151. }
  1152. }
  1153. //
  1154. // Get past an optional 0x or 0X for base 16 mode.
  1155. //
  1156. ValidCharacterFound = FALSE;
  1157. if (((Base == 0) || (Base == 16)) && (Character == '0')) {
  1158. //
  1159. // Seeing a leading zero is an indication of octal mode, so start with
  1160. // that in case the x coming up isn't there.
  1161. //
  1162. if (Base == 0) {
  1163. Base = 8;
  1164. }
  1165. if (FieldSize == 0) {
  1166. Status = STATUS_INVALID_SEQUENCE;
  1167. goto ScanIntegerEnd;
  1168. }
  1169. CharacterCount += 1;
  1170. FieldSize -= 1;
  1171. ValidCharacterFound = TRUE;
  1172. Result = RtlpScannerGetInput(Input, &Character);
  1173. if ((Result == FALSE) || (Character == '\0') || (FieldSize == 0)) {
  1174. *CharactersConsumed = CharacterCount;
  1175. Status = STATUS_SUCCESS;
  1176. goto ScanIntegerEnd;
  1177. }
  1178. //
  1179. // Swallow an x. 0x by itself is allowed, and counts as just the zero.
  1180. //
  1181. if ((Character == 'x') || (Character == 'X')) {
  1182. Base = 16;
  1183. Result = RtlpScannerGetInput(Input, &Character);
  1184. if ((Result == FALSE) ||
  1185. (RtlIsCharacterHexDigit(Character) == FALSE) ||
  1186. (FieldSize == 0)) {
  1187. *CharactersConsumed = CharacterCount;
  1188. Status = STATUS_SUCCESS;
  1189. goto ScanIntegerEnd;
  1190. }
  1191. CharacterCount += 1;
  1192. FieldSize -= 1;
  1193. }
  1194. }
  1195. //
  1196. // If the base is undecided, take a look at the first digit to figure it
  1197. // out.
  1198. //
  1199. if (Base == 0) {
  1200. ASSERT(Character != '0');
  1201. if ((Character >= '1') && (Character <= '9')) {
  1202. Base = 10;
  1203. } else {
  1204. Status = STATUS_INVALID_SEQUENCE;
  1205. goto ScanIntegerEnd;
  1206. }
  1207. }
  1208. //
  1209. // Compute the maximum digit or letter value.
  1210. //
  1211. ASSERT(Base != 0);
  1212. if (Base <= 10) {
  1213. MaxDigit = '0' + Base - 1;
  1214. MaxLetter = 'A' - 1;
  1215. } else {
  1216. MaxDigit = '9';
  1217. MaxLetter = 'A' + Base - 1 - 10;
  1218. }
  1219. Status = STATUS_SUCCESS;
  1220. Value = 0;
  1221. //
  1222. // Loop through every digit.
  1223. //
  1224. while (TRUE) {
  1225. //
  1226. // Uppercase any letters.
  1227. //
  1228. if ((Character >= 'a') && (Character <= 'z')) {
  1229. Character = 'A' + Character - 'a';
  1230. }
  1231. //
  1232. // Potentially add the next digit.
  1233. //
  1234. if ((Character >= '0') && (Character <= '9')) {
  1235. if (Character > MaxDigit) {
  1236. break;
  1237. }
  1238. Character -= '0';
  1239. //
  1240. // It could also be a letter digit.
  1241. //
  1242. } else if ((Character >= 'A') && (Character <= 'Z')) {
  1243. if (Character > MaxLetter) {
  1244. break;
  1245. }
  1246. Character -= 'A' - 0xA;
  1247. //
  1248. // Or it could be something entirely different, in which case the
  1249. // number is over.
  1250. //
  1251. } else {
  1252. break;
  1253. }
  1254. //
  1255. // Check for overflow by dividing back out.
  1256. //
  1257. NewValue = (Value * Base) + Character;
  1258. if (((NewValue - Character) / Base) != Value) {
  1259. Status = STATUS_INTEGER_OVERFLOW;
  1260. }
  1261. Value = NewValue;
  1262. ValidCharacterFound = TRUE;
  1263. CharacterCount += 1;
  1264. FieldSize -= 1;
  1265. if (FieldSize == 0) {
  1266. break;
  1267. }
  1268. Result = RtlpScannerGetInput(Input, &Character);
  1269. if ((Result == FALSE) || (Character == '\0')) {
  1270. break;
  1271. }
  1272. }
  1273. //
  1274. // If the loop broke without ever finding a valid character, fail.
  1275. //
  1276. if (ValidCharacterFound == FALSE) {
  1277. Status = STATUS_INVALID_SEQUENCE;
  1278. goto ScanIntegerEnd;
  1279. }
  1280. //
  1281. // If the character that caused the loop to break wasn't an integer, put
  1282. // the candle back.
  1283. //
  1284. if ((FieldSize != 0) && (Result != FALSE)) {
  1285. RtlpScannerUnput(Input, Character);
  1286. }
  1287. *CharactersConsumed = CharacterCount;
  1288. //
  1289. // Handle overflow.
  1290. //
  1291. if (Status == STATUS_INTEGER_OVERFLOW) {
  1292. if (Signed != FALSE) {
  1293. if (Negative != FALSE) {
  1294. *Integer = MIN_LONGLONG;
  1295. } else {
  1296. *Integer = MAX_LONGLONG;
  1297. }
  1298. } else {
  1299. *(PULONGLONG)Integer = MAX_ULONGLONG;
  1300. }
  1301. } else {
  1302. if (Negative != FALSE) {
  1303. Value = -Value;
  1304. }
  1305. *Integer = Value;
  1306. }
  1307. ScanIntegerEnd:
  1308. if ((!KSUCCESS(Status)) && (Result != FALSE)) {
  1309. RtlpScannerUnput(Input, Character);
  1310. }
  1311. return Status;
  1312. }
  1313. KSTATUS
  1314. RtlpScanDouble (
  1315. PSCAN_INPUT Input,
  1316. ULONG FieldSize,
  1317. double *Double,
  1318. PULONG CharactersConsumed
  1319. )
  1320. /*++
  1321. Routine Description:
  1322. This routine converts a string into a floating point double. It scans past
  1323. leading whitespace.
  1324. Arguments:
  1325. Input - Supplies a pointer to the filled out scan input structure which
  1326. will be used to retrieve more input.
  1327. FieldSize - Supplies the maximum number of characters to scan for the
  1328. double.
  1329. Double - Supplies a pointer where the resulting double is returned on
  1330. success.
  1331. CharactersConsumed - Supplies a pointer where the number characters consumed
  1332. will be stored.
  1333. Return Value:
  1334. STATUS_SUCCESS if an integer was successfully scanned.
  1335. STATUS_INVALID_SEQUENCE if a valid double could not be scanned.
  1336. STATUS_OUT_OF_BOUNDS if the exponent was out of range.
  1337. STATUS_END_OF_FILE if the end of the file was reached before any
  1338. non-whitespace could be retrieved.
  1339. --*/
  1340. {
  1341. double Base;
  1342. CHAR Character;
  1343. ULONG CharacterCount;
  1344. CHAR DecasedCharacter;
  1345. double Digit;
  1346. LONG Exponent;
  1347. CHAR ExponentCharacter;
  1348. double ExponentMultiplier;
  1349. CHAR ExponentSign;
  1350. double ExponentValue;
  1351. BOOL Negative;
  1352. double NegativeExponent;
  1353. double OneOverBase;
  1354. ULONG PowerIndex;
  1355. BOOL Result;
  1356. BOOL SeenDecimal;
  1357. KSTATUS Status;
  1358. CHAR String[DOUBLE_SCAN_STRING_SIZE];
  1359. ULONG StringCharacterCount;
  1360. BOOL ValidCharacterFound;
  1361. double Value;
  1362. Base = 10.0;
  1363. OneOverBase = 1.0E-1;
  1364. *CharactersConsumed = 0;
  1365. CharacterCount = 0;
  1366. *Double = 0.0;
  1367. Negative = FALSE;
  1368. Value = 0.0;
  1369. Result = RtlpScannerGetInput(Input, &Character);
  1370. if ((Result == FALSE) || (Character == '\0')) {
  1371. return STATUS_END_OF_FILE;
  1372. }
  1373. //
  1374. // Scan past any whitespace.
  1375. //
  1376. while (RtlIsCharacterSpace(Character) != FALSE) {
  1377. CharacterCount += 1;
  1378. Result = RtlpScannerGetInput(Input, &Character);
  1379. if ((Result == FALSE) || (Character == '\0')) {
  1380. return STATUS_END_OF_FILE;
  1381. }
  1382. }
  1383. Status = STATUS_SUCCESS;
  1384. //
  1385. // Get past any optional plus or minus.
  1386. //
  1387. if ((Character == '+') || (Character == '-')) {
  1388. if (Character == '-') {
  1389. Negative = TRUE;
  1390. }
  1391. if (FieldSize == 0) {
  1392. Status = STATUS_INVALID_SEQUENCE;
  1393. goto ScanDoubleEnd;
  1394. }
  1395. CharacterCount += 1;
  1396. FieldSize -= 1;
  1397. Result = RtlpScannerGetInput(Input, &Character);
  1398. if ((Result == FALSE) || (Character == '\0') || (FieldSize == 0)) {
  1399. return STATUS_INVALID_SEQUENCE;
  1400. }
  1401. }
  1402. //
  1403. // Look for inf and infinity, ignoring case.
  1404. //
  1405. StringCharacterCount = 0;
  1406. DecasedCharacter = Character;
  1407. if ((Character >= 'A') && (Character <= 'Z')) {
  1408. DecasedCharacter = Character + 'a' - 'A';
  1409. }
  1410. while ((StringCharacterCount < sizeof(INFINITY_STRING) - 1) &&
  1411. (DecasedCharacter == INFINITY_STRING[StringCharacterCount])) {
  1412. String[StringCharacterCount] = Character;
  1413. StringCharacterCount += 1;
  1414. CharacterCount += 1;
  1415. FieldSize -= 1;
  1416. if (FieldSize == 0) {
  1417. break;
  1418. }
  1419. Result = RtlpScannerGetInput(Input, &Character);
  1420. if ((Result == FALSE) || (Character == '\0')) {
  1421. break;
  1422. }
  1423. DecasedCharacter = Character;
  1424. if ((Character >= 'A') && (Character <= 'Z')) {
  1425. DecasedCharacter = Character + 'a' - 'A';
  1426. }
  1427. }
  1428. if (StringCharacterCount >= 3) {
  1429. //
  1430. // If it didn't match the full infinity (but has matched inf), then
  1431. // put back anything between inf and the failed infinity.
  1432. //
  1433. if (StringCharacterCount != sizeof(INFINITY_STRING) - 1) {
  1434. RtlpScannerUnput(Input, Character);
  1435. while (StringCharacterCount > 3) {
  1436. RtlpScannerUnput(Input, String[StringCharacterCount]);
  1437. StringCharacterCount -= 1;
  1438. CharacterCount -= 1;
  1439. }
  1440. }
  1441. Value = DOUBLE_INFINITY;
  1442. goto ScanDoubleEnd;
  1443. //
  1444. // Unput all the characters looked at.
  1445. //
  1446. } else if (StringCharacterCount != 0) {
  1447. RtlpScannerUnput(Input, Character);
  1448. StringCharacterCount -= 1;
  1449. CharacterCount -= 1;
  1450. while (StringCharacterCount != 0) {
  1451. RtlpScannerUnput(Input, String[StringCharacterCount]);
  1452. StringCharacterCount -= 1;
  1453. CharacterCount -= 1;
  1454. }
  1455. Character = String[0];
  1456. }
  1457. //
  1458. // Also look for NaN.
  1459. //
  1460. DecasedCharacter = Character;
  1461. if ((Character >= 'A') && (Character <= 'Z')) {
  1462. DecasedCharacter = Character + 'a' - 'A';
  1463. }
  1464. while ((StringCharacterCount < sizeof(NAN_STRING) - 1) &&
  1465. (DecasedCharacter == NAN_STRING[StringCharacterCount])) {
  1466. String[StringCharacterCount] = Character;
  1467. StringCharacterCount += 1;
  1468. CharacterCount += 1;
  1469. FieldSize -= 1;
  1470. if (FieldSize == 0) {
  1471. break;
  1472. }
  1473. Result = RtlpScannerGetInput(Input, &Character);
  1474. if ((Result == FALSE) || (Character == '\0')) {
  1475. break;
  1476. }
  1477. DecasedCharacter = Character;
  1478. if ((Character >= 'A') && (Character <= 'Z')) {
  1479. DecasedCharacter = Character + 'a' - 'A';
  1480. }
  1481. }
  1482. if (StringCharacterCount == sizeof(NAN_STRING) - 1) {
  1483. //
  1484. // Also check for a () or (0) on the end.
  1485. //
  1486. if (Character == '(') {
  1487. Result = RtlpScannerGetInput(Input, &Character);
  1488. if (Result != FALSE) {
  1489. if (Character == '0') {
  1490. Result = RtlpScannerGetInput(Input, &Character);
  1491. if (Result != FALSE) {
  1492. if (Character == ')') {
  1493. CharacterCount += 3;
  1494. } else {
  1495. RtlpScannerUnput(Input, Character);
  1496. RtlpScannerUnput(Input, '0');
  1497. RtlpScannerUnput(Input, '(');
  1498. }
  1499. } else {
  1500. RtlpScannerUnput(Input, Character);
  1501. RtlpScannerUnput(Input, '(');
  1502. }
  1503. } else if (Character == ')') {
  1504. CharacterCount += 2;
  1505. } else {
  1506. RtlpScannerUnput(Input, Character);
  1507. RtlpScannerUnput(Input, '(');
  1508. }
  1509. } else {
  1510. RtlpScannerUnput(Input, Character);
  1511. }
  1512. } else {
  1513. RtlpScannerUnput(Input, Character);
  1514. }
  1515. Value = DOUBLE_NAN;
  1516. Negative = FALSE;
  1517. goto ScanDoubleEnd;
  1518. //
  1519. // Unput all the characters looked at.
  1520. //
  1521. } else if (StringCharacterCount != 0) {
  1522. RtlpScannerUnput(Input, Character);
  1523. StringCharacterCount -= 1;
  1524. CharacterCount -= 1;
  1525. while (StringCharacterCount != 0) {
  1526. RtlpScannerUnput(Input, String[StringCharacterCount]);
  1527. StringCharacterCount -= 1;
  1528. CharacterCount -= 1;
  1529. }
  1530. Character = String[0];
  1531. }
  1532. //
  1533. // Get past an optional 0x or 0X for base 16 mode.
  1534. //
  1535. ValidCharacterFound = FALSE;
  1536. if (Character == '0') {
  1537. ValidCharacterFound = TRUE;
  1538. if (FieldSize == 0) {
  1539. Status = STATUS_INVALID_SEQUENCE;
  1540. goto ScanDoubleEnd;
  1541. }
  1542. CharacterCount += 1;
  1543. FieldSize -= 1;
  1544. Result = RtlpScannerGetInput(Input, &Character);
  1545. if (Result != FALSE) {
  1546. //
  1547. // If it was only a lonely zero, then handle that case specifically.
  1548. //
  1549. if ((FieldSize == 0) ||
  1550. (Character == '\0') ||
  1551. (RtlIsCharacterSpace(Character) != FALSE)) {
  1552. *CharactersConsumed = CharacterCount;
  1553. goto ScanDoubleEnd;
  1554. }
  1555. if ((Character == 'x') || (Character == 'X')) {
  1556. Base = 16.0;
  1557. OneOverBase = 0.0625;
  1558. Result = RtlpScannerGetInput(Input, &Character);
  1559. //
  1560. // If it was just an 0x, then actually it was just a 0.
  1561. //
  1562. if ((Result == FALSE) ||
  1563. (RtlIsCharacterHexDigit(Character) == FALSE)) {
  1564. RtlpScannerUnput(Input, Character);
  1565. goto ScanDoubleEnd;
  1566. }
  1567. CharacterCount += 1;
  1568. FieldSize -= 1;
  1569. if (FieldSize == 0) {
  1570. Status = STATUS_INVALID_SEQUENCE;
  1571. goto ScanDoubleEnd;
  1572. }
  1573. }
  1574. }
  1575. }
  1576. Digit = 0.0;
  1577. NegativeExponent = OneOverBase;
  1578. //
  1579. // Loop through every digit.
  1580. //
  1581. SeenDecimal = FALSE;
  1582. while (TRUE) {
  1583. //
  1584. // Uppercase any letters.
  1585. //
  1586. if ((Character >= 'a') && (Character <= 'z')) {
  1587. Character = 'A' + Character - 'a';
  1588. }
  1589. //
  1590. // Potentially add the next digit.
  1591. //
  1592. if ((Character >= '0') && (Character <= '9')) {
  1593. Digit = Character - '0';
  1594. //
  1595. // It could also be a letter digit.
  1596. //
  1597. } else if ((Base == 16.0) && (Character >= 'A') && (Character <= 'F')) {
  1598. Digit = Character - 'A' + 10;
  1599. //
  1600. // Handle a decimal point. Hopefully it was the the first and only one.
  1601. //
  1602. } else if (Character == '.') {
  1603. if (SeenDecimal != FALSE) {
  1604. break;
  1605. }
  1606. SeenDecimal = TRUE;
  1607. //
  1608. // Or it could be something entirely different, in which case the
  1609. // number is over.
  1610. //
  1611. } else {
  1612. break;
  1613. }
  1614. if (Character != '.') {
  1615. //
  1616. // If a decimal point has not been seen yet, this is the next
  1617. // integer digit, so multiply everything by the base and add
  1618. // this digit.
  1619. //
  1620. if (SeenDecimal == FALSE) {
  1621. Value = (Value * Base) + Digit;
  1622. //
  1623. // This is a fractional part, so multiply it by the current
  1624. // negative exponent, add it to the value, and shrink down to the
  1625. // next exponent.
  1626. //
  1627. } else {
  1628. Value += Digit * NegativeExponent;
  1629. NegativeExponent *= OneOverBase;
  1630. }
  1631. ValidCharacterFound = TRUE;
  1632. }
  1633. CharacterCount += 1;
  1634. FieldSize -= 1;
  1635. if (FieldSize == 0) {
  1636. goto ScanDoubleEnd;
  1637. }
  1638. Result = RtlpScannerGetInput(Input, &Character);
  1639. if ((Result == FALSE) || (Character == '\0')) {
  1640. break;
  1641. }
  1642. }
  1643. //
  1644. // If the loop broke without ever finding a valid character, fail.
  1645. //
  1646. if (ValidCharacterFound == FALSE) {
  1647. CharacterCount = 0;
  1648. Status = STATUS_INVALID_SEQUENCE;
  1649. goto ScanDoubleEnd;
  1650. }
  1651. if (FieldSize == 0) {
  1652. goto ScanDoubleEnd;
  1653. }
  1654. //
  1655. // Look for an exponent character, and if none is found, finish.
  1656. //
  1657. ExponentCharacter = 0;
  1658. if (((Base == 10.0) && ((Character == 'e') || (Character == 'E'))) ||
  1659. ((Base == 16.0) && ((Character == 'p') || (Character == 'P')))) {
  1660. ExponentCharacter = Character;
  1661. }
  1662. if (ExponentCharacter == 0) {
  1663. RtlpScannerUnput(Input, Character);
  1664. goto ScanDoubleEnd;
  1665. }
  1666. CharacterCount += 1;
  1667. FieldSize -= 1;
  1668. if (FieldSize == 0) {
  1669. goto ScanDoubleEnd;
  1670. }
  1671. Result = RtlpScannerGetInput(Input, &Character);
  1672. if ((Result == FALSE) || (Character == '\0')) {
  1673. RtlpScannerUnput(Input, ExponentCharacter);
  1674. CharacterCount -= 1;
  1675. goto ScanDoubleEnd;
  1676. }
  1677. //
  1678. // Look for an optional plus or minus.
  1679. //
  1680. ExponentSign = 0;
  1681. if ((Character == '+') || (Character == '-')) {
  1682. ExponentSign = Character;
  1683. CharacterCount += 1;
  1684. FieldSize -= 1;
  1685. if (FieldSize == 0) {
  1686. goto ScanDoubleEnd;
  1687. }
  1688. Result = RtlpScannerGetInput(Input, &Character);
  1689. if ((Result == FALSE) || (Character == '\0')) {
  1690. RtlpScannerUnput(Input, ExponentSign);
  1691. RtlpScannerUnput(Input, ExponentCharacter);
  1692. CharacterCount -= 2;
  1693. goto ScanDoubleEnd;
  1694. }
  1695. }
  1696. //
  1697. // If there are not exponent digits, the exponent and sign were a fakeout.
  1698. //
  1699. if (!((Character >= '0') && (Character <= '9'))) {
  1700. RtlpScannerUnput(Input, Character);
  1701. if (ExponentSign != 0) {
  1702. RtlpScannerUnput(Input, ExponentSign);
  1703. CharacterCount -= 1;
  1704. }
  1705. RtlpScannerUnput(Input, ExponentCharacter);
  1706. CharacterCount -= 1;
  1707. goto ScanDoubleEnd;
  1708. }
  1709. //
  1710. // Scan the base decimal integer exponent (meaning the exponent is always
  1711. // a string in base 10).
  1712. //
  1713. Exponent = 0;
  1714. while ((Character >= '0') && (Character <= '9')) {
  1715. Exponent = (Exponent * 10) + (Character - '0');
  1716. CharacterCount += 1;
  1717. FieldSize -= 1;
  1718. if (FieldSize == 0) {
  1719. break;
  1720. }
  1721. Result = RtlpScannerGetInput(Input, &Character);
  1722. if ((Result == FALSE) || (Character == '\0')) {
  1723. break;
  1724. }
  1725. }
  1726. //
  1727. // If the character that caused the loop to break wasn't an integer, put.
  1728. // the candle. back.
  1729. //
  1730. if ((FieldSize != 0) && (Result != FALSE)) {
  1731. RtlpScannerUnput(Input, Character);
  1732. }
  1733. if (Exponent > 300) {
  1734. if (Value == 0.0) {
  1735. goto ScanDoubleEnd;
  1736. }
  1737. Status = STATUS_OUT_OF_BOUNDS;
  1738. Result = FALSE;
  1739. if (ExponentSign == '-') {
  1740. Value = 0.0;
  1741. } else {
  1742. Value = DOUBLE_HUGE_VALUE;
  1743. }
  1744. goto ScanDoubleEnd;
  1745. }
  1746. //
  1747. // Create a value with the desired exponent.
  1748. //
  1749. if (Base == 10.0) {
  1750. //
  1751. // Put together the approximation using powers of 2.
  1752. //
  1753. if (ExponentSign == '-') {
  1754. ExponentValue = RtlFirst16NegativePowersOf10[Exponent & 0x0F];
  1755. } else {
  1756. ExponentValue = RtlFirst16PowersOf10[Exponent & 0x0F];
  1757. }
  1758. Exponent = Exponent >> 4;
  1759. for (PowerIndex = 0; PowerIndex < 5; PowerIndex += 1) {
  1760. if (Exponent == 0) {
  1761. break;
  1762. }
  1763. if ((Exponent & 0x1) != 0) {
  1764. if (ExponentSign == '-') {
  1765. ExponentValue *= RtlNegativePowersOf2[PowerIndex];
  1766. } else {
  1767. ExponentValue *= RtlPositivePowersOf2[PowerIndex];
  1768. }
  1769. }
  1770. Exponent = Exponent >> 1;
  1771. }
  1772. //
  1773. // For base 16, just multiply the power of 2 out.
  1774. //
  1775. } else {
  1776. ExponentValue = 1.0;
  1777. if (ExponentSign == '-') {
  1778. ExponentMultiplier = 0.5;
  1779. } else {
  1780. ExponentMultiplier = 2.0;
  1781. }
  1782. while (Exponent != 0) {
  1783. ExponentValue *= ExponentMultiplier;
  1784. Exponent -= 1;
  1785. }
  1786. }
  1787. Value *= ExponentValue;
  1788. ScanDoubleEnd:
  1789. if ((!KSUCCESS(Status)) && (Result != FALSE)) {
  1790. RtlpScannerUnput(Input, Character);
  1791. }
  1792. *CharactersConsumed = CharacterCount;
  1793. if (Negative != FALSE) {
  1794. Value = -Value;
  1795. }
  1796. *Double = Value;
  1797. return Status;
  1798. }
  1799. VOID
  1800. RtlpScannerUnput (
  1801. PSCAN_INPUT Input,
  1802. CHAR Character
  1803. )
  1804. /*++
  1805. Routine Description:
  1806. This routine puts a byte of input back into the scanner's input stream.
  1807. Arguments:
  1808. Input - Supplies a pointer to the input scanner structure.
  1809. Character - Supplies the character to put back.
  1810. Return Value:
  1811. None.
  1812. --*/
  1813. {
  1814. ASSERT(Input->ValidUnputCharacters < SCANNER_UNPUT_SIZE);
  1815. Input->UnputCharacters[Input->ValidUnputCharacters] = Character;
  1816. Input->ValidUnputCharacters += 1;
  1817. return;
  1818. }
  1819. VOID
  1820. RtlpScannerWideUnput (
  1821. PSCAN_INPUT Input,
  1822. WCHAR Character
  1823. )
  1824. /*++
  1825. Routine Description:
  1826. This routine puts a wide character of input back into a byte-oriented
  1827. scanner's input stream.
  1828. Arguments:
  1829. Input - Supplies a pointer to the input scanner structure.
  1830. Character - Supplies the character to put back.
  1831. Return Value:
  1832. None.
  1833. --*/
  1834. {
  1835. CHAR Buffer[MULTIBYTE_MAX];
  1836. ULONG BufferSize;
  1837. ULONG ByteIndex;
  1838. KSTATUS Status;
  1839. ASSERT(Input->ValidUnputCharacters < SCANNER_UNPUT_SIZE);
  1840. BufferSize = MULTIBYTE_MAX;
  1841. Status = RtlConvertWideCharacterToMultibyte(Character,
  1842. Buffer,
  1843. &BufferSize,
  1844. &(Input->State));
  1845. if (KSUCCESS(Status)) {
  1846. for (ByteIndex = 0; ByteIndex < BufferSize; ByteIndex += 1) {
  1847. if (Input->ValidUnputCharacters >= SCANNER_UNPUT_SIZE) {
  1848. break;
  1849. }
  1850. Input->UnputCharacters[Input->ValidUnputCharacters] =
  1851. Buffer[ByteIndex];
  1852. Input->ValidUnputCharacters += 1;
  1853. }
  1854. }
  1855. return;
  1856. }
  1857. BOOL
  1858. RtlpScannerGetInput (
  1859. PSCAN_INPUT Input,
  1860. PCHAR Character
  1861. )
  1862. /*++
  1863. Routine Description:
  1864. This routine retrieves another byte of input from the input scanner.
  1865. Arguments:
  1866. Input - Supplies a pointer to the input scanner structure.
  1867. Character - Supplies a pointer where the character will be returned on
  1868. success.
  1869. Return Value:
  1870. TRUE if a character was read.
  1871. FALSE if the end of the file or string was encountered.
  1872. --*/
  1873. {
  1874. if (Input->ValidUnputCharacters != 0) {
  1875. *Character = Input->UnputCharacters[Input->ValidUnputCharacters - 1];
  1876. Input->ValidUnputCharacters -= 1;
  1877. return TRUE;
  1878. }
  1879. return Input->ReadU.GetInput(Input, Character);
  1880. }
  1881. BOOL
  1882. RtlpScannerGetWideInput (
  1883. PSCAN_INPUT Input,
  1884. PWCHAR WideCharacter
  1885. )
  1886. /*++
  1887. Routine Description:
  1888. This routine retrieves wide input character from a byte oriented scanner
  1889. input.
  1890. Arguments:
  1891. Input - Supplies a pointer to the input scanner structure.
  1892. WideCharacter - Supplies a pointer where the wide character will be
  1893. returned on success.
  1894. Return Value:
  1895. TRUE if a character was read.
  1896. FALSE if the end of the file or string was encountered.
  1897. --*/
  1898. {
  1899. PSTR Buffer;
  1900. ULONG BufferSize;
  1901. CHAR MultibyteBuffer[MULTIBYTE_MAX];
  1902. ULONG MultibyteBufferSize;
  1903. BOOL Result;
  1904. KSTATUS Status;
  1905. MultibyteBufferSize = 0;
  1906. while (TRUE) {
  1907. Result = RtlpScannerGetInput(Input,
  1908. &(MultibyteBuffer[MultibyteBufferSize]));
  1909. if (Result == FALSE) {
  1910. return FALSE;
  1911. }
  1912. MultibyteBufferSize += 1;
  1913. Buffer = MultibyteBuffer;
  1914. BufferSize = MultibyteBufferSize;
  1915. Status = RtlConvertMultibyteCharacterToWide(&Buffer,
  1916. &BufferSize,
  1917. WideCharacter,
  1918. &(Input->State));
  1919. if (KSUCCESS(Status)) {
  1920. break;
  1921. } else if (Status != STATUS_BUFFER_TOO_SMALL) {
  1922. return FALSE;
  1923. }
  1924. if (MultibyteBufferSize >= MULTIBYTE_MAX) {
  1925. ASSERT(FALSE);
  1926. return FALSE;
  1927. }
  1928. }
  1929. return TRUE;
  1930. }
  1931. BOOL
  1932. RtlpStringScannerGetInput (
  1933. PSCAN_INPUT Input,
  1934. PCHAR Character
  1935. )
  1936. /*++
  1937. Routine Description:
  1938. This routine retrieves another byte of input from the input scanner for a
  1939. string based scanner.
  1940. Arguments:
  1941. Input - Supplies a pointer to the input scanner structure.
  1942. Character - Supplies a pointer where the character will be returned on
  1943. success.
  1944. Return Value:
  1945. TRUE if a character was read.
  1946. FALSE if the end of the file or string was encountered.
  1947. --*/
  1948. {
  1949. if (Input->StringSize == 0) {
  1950. return FALSE;
  1951. }
  1952. Input->CharactersRead += 1;
  1953. Input->StringSize -= 1;
  1954. *Character = *(Input->DataU.String);
  1955. Input->DataU.String += 1;
  1956. return TRUE;
  1957. }