2c0cd5a55a8f9014c8d9cfb276d2a414a4ff0a7a
[reactos.git] / base / setup / usetup / partlist.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2003, 2004, 2005 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: base/setup/usetup/partlist.c
23 * PURPOSE: Partition list functions
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 */
26
27 #include "usetup.h"
28
29 #define NDEBUG
30 #include <debug.h>
31
32 /* HELPERS FOR PARTITION TYPES **********************************************/
33
34 VOID
35 GetPartTypeStringFromPartitionType(
36 IN UCHAR partitionType,
37 OUT PCHAR strPartType,
38 IN ULONG cchPartType)
39 {
40 /* Determine partition type */
41
42 if (IsContainerPartition(partitionType))
43 {
44 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_EXTENDED_PARTITION));
45 }
46 else if (partitionType == PARTITION_ENTRY_UNUSED)
47 {
48 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_FORMATUNUSED));
49 }
50 else
51 {
52 UINT i;
53
54 /* Do the table lookup */
55 for (i = 0; i < ARRAYSIZE(PartitionTypes); i++)
56 {
57 if (partitionType == PartitionTypes[i].Type)
58 {
59 RtlStringCchCopyA(strPartType, cchPartType, PartitionTypes[i].Description);
60 return;
61 }
62 }
63
64 /* We are here because the partition type is unknown */
65 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_FORMATUNKNOWN));
66 }
67 }
68
69
70 /* FUNCTIONS ****************************************************************/
71
72 VOID
73 InitPartitionListUi(
74 IN OUT PPARTLIST_UI ListUi,
75 IN PPARTLIST List,
76 IN SHORT Left,
77 IN SHORT Top,
78 IN SHORT Right,
79 IN SHORT Bottom)
80 {
81 ListUi->List = List;
82 // ListUi->FirstShown = NULL;
83 // ListUi->LastShown = NULL;
84
85 ListUi->Left = Left;
86 ListUi->Top = Top;
87 ListUi->Right = Right;
88 ListUi->Bottom = Bottom;
89
90 ListUi->Line = 0;
91 ListUi->Offset = 0;
92
93 // ListUi->Redraw = TRUE;
94 }
95
96 static
97 VOID
98 PrintEmptyLine(
99 IN PPARTLIST_UI ListUi)
100 {
101 COORD coPos;
102 ULONG Written;
103 USHORT Width;
104 USHORT Height;
105
106 Width = ListUi->Right - ListUi->Left - 1;
107 Height = ListUi->Bottom - ListUi->Top - 2;
108
109 coPos.X = ListUi->Left + 1;
110 coPos.Y = ListUi->Top + 1 + ListUi->Line;
111
112 if (ListUi->Line >= 0 && ListUi->Line <= Height)
113 {
114 FillConsoleOutputAttribute(StdOutput,
115 FOREGROUND_WHITE | BACKGROUND_BLUE,
116 Width,
117 coPos,
118 &Written);
119
120 FillConsoleOutputCharacterA(StdOutput,
121 ' ',
122 Width,
123 coPos,
124 &Written);
125 }
126
127 ListUi->Line++;
128 }
129
130 static
131 VOID
132 PrintPartitionData(
133 IN PPARTLIST_UI ListUi,
134 IN PDISKENTRY DiskEntry,
135 IN PPARTENTRY PartEntry)
136 {
137 PPARTLIST List = ListUi->List;
138 CHAR LineBuffer[128];
139 COORD coPos;
140 ULONG Written;
141 USHORT Width;
142 USHORT Height;
143 LARGE_INTEGER PartSize;
144 PCHAR Unit;
145 UCHAR Attribute;
146 CHAR PartTypeString[32];
147 PCHAR PartType = PartTypeString;
148
149 Width = ListUi->Right - ListUi->Left - 1;
150 Height = ListUi->Bottom - ListUi->Top - 2;
151
152 coPos.X = ListUi->Left + 1;
153 coPos.Y = ListUi->Top + 1 + ListUi->Line;
154
155 /* Get the partition size */
156 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
157 #if 0
158 if (PartSize.QuadPart >= 10 * GB) /* 10 GB */
159 {
160 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, GB);
161 Unit = MUIGetString(STRING_GB);
162 }
163 else
164 #endif
165 if (PartSize.QuadPart >= 10 * MB) /* 10 MB */
166 {
167 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, MB);
168 Unit = MUIGetString(STRING_MB);
169 }
170 else
171 {
172 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, KB);
173 Unit = MUIGetString(STRING_KB);
174 }
175
176 if (PartEntry->IsPartitioned == FALSE)
177 {
178 sprintf(LineBuffer,
179 MUIGetString(STRING_UNPSPACE),
180 PartEntry->LogicalPartition ? " " : "",
181 PartEntry->LogicalPartition ? "" : " ",
182 PartSize.u.LowPart,
183 Unit);
184 }
185 else
186 {
187 /* Determine partition type */
188 PartTypeString[0] = '\0';
189 if (PartEntry->New != FALSE)
190 {
191 PartType = MUIGetString(STRING_UNFORMATTED);
192 }
193 else if (PartEntry->IsPartitioned != FALSE)
194 {
195 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
196 PartTypeString,
197 ARRAYSIZE(PartTypeString));
198 PartType = PartTypeString;
199 }
200
201 if (strcmp(PartType, MUIGetString(STRING_FORMATUNKNOWN)) == 0)
202 {
203 sprintf(LineBuffer,
204 MUIGetString(STRING_HDDINFOUNK5),
205 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
206 (PartEntry->DriveLetter == 0) ? '-' : ':',
207 PartEntry->BootIndicator ? '*' : ' ',
208 PartEntry->LogicalPartition ? " " : "",
209 PartEntry->PartitionType,
210 PartEntry->LogicalPartition ? "" : " ",
211 PartSize.u.LowPart,
212 Unit);
213 }
214 else
215 {
216 sprintf(LineBuffer,
217 "%c%c %c %s%-24s%s %6lu %s",
218 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
219 (PartEntry->DriveLetter == 0) ? '-' : ':',
220 PartEntry->BootIndicator ? '*' : ' ',
221 PartEntry->LogicalPartition ? " " : "",
222 PartType,
223 PartEntry->LogicalPartition ? "" : " ",
224 PartSize.u.LowPart,
225 Unit);
226 }
227 }
228
229 Attribute = (List->CurrentDisk == DiskEntry &&
230 List->CurrentPartition == PartEntry) ?
231 FOREGROUND_BLUE | BACKGROUND_WHITE :
232 FOREGROUND_WHITE | BACKGROUND_BLUE;
233
234 if (ListUi->Line >= 0 && ListUi->Line <= Height)
235 {
236 FillConsoleOutputCharacterA(StdOutput,
237 ' ',
238 Width,
239 coPos,
240 &Written);
241 }
242 coPos.X += 4;
243 Width -= 8;
244 if (ListUi->Line >= 0 && ListUi->Line <= Height)
245 {
246 FillConsoleOutputAttribute(StdOutput,
247 Attribute,
248 Width,
249 coPos,
250 &Written);
251 }
252 coPos.X++;
253 Width -= 2;
254 if (ListUi->Line >= 0 && ListUi->Line <= Height)
255 {
256 WriteConsoleOutputCharacterA(StdOutput,
257 LineBuffer,
258 min(strlen(LineBuffer), Width),
259 coPos,
260 &Written);
261 }
262
263 ListUi->Line++;
264 }
265
266 static
267 VOID
268 PrintDiskData(
269 IN PPARTLIST_UI ListUi,
270 IN PDISKENTRY DiskEntry)
271 {
272 // PPARTLIST List = ListUi->List;
273 PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
274 PLIST_ENTRY PrimaryEntry, LogicalEntry;
275 CHAR LineBuffer[128];
276 COORD coPos;
277 ULONG Written;
278 USHORT Width;
279 USHORT Height;
280 ULARGE_INTEGER DiskSize;
281 PCHAR Unit;
282
283 Width = ListUi->Right - ListUi->Left - 1;
284 Height = ListUi->Bottom - ListUi->Top - 2;
285
286 coPos.X = ListUi->Left + 1;
287 coPos.Y = ListUi->Top + 1 + ListUi->Line;
288
289 DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
290 if (DiskSize.QuadPart >= 10 * GB) /* 10 GB */
291 {
292 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, GB);
293 Unit = MUIGetString(STRING_GB);
294 }
295 else
296 {
297 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, MB);
298 if (DiskSize.QuadPart == 0)
299 DiskSize.QuadPart = 1;
300 Unit = MUIGetString(STRING_MB);
301 }
302
303 //
304 // FIXME: We *MUST* use TXTSETUP.SIF strings from section "DiskDriverMap" !!
305 //
306 if (DiskEntry->DriverName.Length > 0)
307 {
308 sprintf(LineBuffer,
309 MUIGetString(STRING_HDINFOPARTSELECT_1),
310 DiskSize.u.LowPart,
311 Unit,
312 DiskEntry->DiskNumber,
313 DiskEntry->Port,
314 DiskEntry->Bus,
315 DiskEntry->Id,
316 &DiskEntry->DriverName,
317 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
318 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
319 "RAW");
320 }
321 else
322 {
323 sprintf(LineBuffer,
324 MUIGetString(STRING_HDINFOPARTSELECT_2),
325 DiskSize.u.LowPart,
326 Unit,
327 DiskEntry->DiskNumber,
328 DiskEntry->Port,
329 DiskEntry->Bus,
330 DiskEntry->Id,
331 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
332 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
333 "RAW");
334 }
335
336 if (ListUi->Line >= 0 && ListUi->Line <= Height)
337 {
338 FillConsoleOutputAttribute(StdOutput,
339 FOREGROUND_WHITE | BACKGROUND_BLUE,
340 Width,
341 coPos,
342 &Written);
343
344 FillConsoleOutputCharacterA(StdOutput,
345 ' ',
346 Width,
347 coPos,
348 &Written);
349 }
350
351 coPos.X++;
352 if (ListUi->Line >= 0 && ListUi->Line <= Height)
353 {
354 WriteConsoleOutputCharacterA(StdOutput,
355 LineBuffer,
356 min((USHORT)strlen(LineBuffer), Width - 2),
357 coPos,
358 &Written);
359 }
360
361 ListUi->Line++;
362
363 /* Print separator line */
364 PrintEmptyLine(ListUi);
365
366 /* Print partition lines */
367 PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
368 while (PrimaryEntry != &DiskEntry->PrimaryPartListHead)
369 {
370 PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
371
372 PrintPartitionData(ListUi,
373 DiskEntry,
374 PrimaryPartEntry);
375
376 if (IsContainerPartition(PrimaryPartEntry->PartitionType))
377 {
378 LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
379 while (LogicalEntry != &DiskEntry->LogicalPartListHead)
380 {
381 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
382
383 PrintPartitionData(ListUi,
384 DiskEntry,
385 LogicalPartEntry);
386
387 LogicalEntry = LogicalEntry->Flink;
388 }
389 }
390
391 PrimaryEntry = PrimaryEntry->Flink;
392 }
393
394 /* Print separator line */
395 PrintEmptyLine(ListUi);
396 }
397
398 VOID
399 DrawPartitionList(
400 IN PPARTLIST_UI ListUi)
401 {
402 PPARTLIST List = ListUi->List;
403 PLIST_ENTRY Entry, Entry2;
404 PDISKENTRY DiskEntry;
405 PPARTENTRY PartEntry = NULL;
406 COORD coPos;
407 ULONG Written;
408 SHORT i;
409 SHORT CurrentDiskLine;
410 SHORT CurrentPartLine;
411 SHORT LastLine;
412 BOOLEAN CurrentPartLineFound = FALSE;
413 BOOLEAN CurrentDiskLineFound = FALSE;
414
415 /* Calculate the line of the current disk and partition */
416 CurrentDiskLine = 0;
417 CurrentPartLine = 0;
418 LastLine = 0;
419
420 Entry = List->DiskListHead.Flink;
421 while (Entry != &List->DiskListHead)
422 {
423 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
424
425 LastLine += 2;
426 if (CurrentPartLineFound == FALSE)
427 {
428 CurrentPartLine += 2;
429 }
430
431 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
432 while (Entry2 != &DiskEntry->PrimaryPartListHead)
433 {
434 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
435 if (PartEntry == List->CurrentPartition)
436 {
437 CurrentPartLineFound = TRUE;
438 }
439
440 Entry2 = Entry2->Flink;
441 if (CurrentPartLineFound == FALSE)
442 {
443 CurrentPartLine++;
444 }
445
446 LastLine++;
447 }
448
449 if (CurrentPartLineFound == FALSE)
450 {
451 Entry2 = DiskEntry->LogicalPartListHead.Flink;
452 while (Entry2 != &DiskEntry->LogicalPartListHead)
453 {
454 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
455 if (PartEntry == List->CurrentPartition)
456 {
457 CurrentPartLineFound = TRUE;
458 }
459
460 Entry2 = Entry2->Flink;
461 if (CurrentPartLineFound == FALSE)
462 {
463 CurrentPartLine++;
464 }
465
466 LastLine++;
467 }
468 }
469
470 if (DiskEntry == List->CurrentDisk)
471 {
472 CurrentDiskLineFound = TRUE;
473 }
474
475 Entry = Entry->Flink;
476 if (Entry != &List->DiskListHead)
477 {
478 if (CurrentDiskLineFound == FALSE)
479 {
480 CurrentPartLine ++;
481 CurrentDiskLine = CurrentPartLine;
482 }
483
484 LastLine++;
485 }
486 else
487 {
488 LastLine--;
489 }
490 }
491
492 /* If it possible, make the disk name visible */
493 if (CurrentPartLine < ListUi->Offset)
494 {
495 ListUi->Offset = CurrentPartLine;
496 }
497 else if (CurrentPartLine - ListUi->Offset > ListUi->Bottom - ListUi->Top - 2)
498 {
499 ListUi->Offset = CurrentPartLine - (ListUi->Bottom - ListUi->Top - 2);
500 }
501
502 if (CurrentDiskLine < ListUi->Offset && CurrentPartLine - CurrentDiskLine < ListUi->Bottom - ListUi->Top - 2)
503 {
504 ListUi->Offset = CurrentDiskLine;
505 }
506
507 /* Draw upper left corner */
508 coPos.X = ListUi->Left;
509 coPos.Y = ListUi->Top;
510 FillConsoleOutputCharacterA(StdOutput,
511 0xDA, // '+',
512 1,
513 coPos,
514 &Written);
515
516 /* Draw upper edge */
517 coPos.X = ListUi->Left + 1;
518 coPos.Y = ListUi->Top;
519 if (ListUi->Offset == 0)
520 {
521 FillConsoleOutputCharacterA(StdOutput,
522 0xC4, // '-',
523 ListUi->Right - ListUi->Left - 1,
524 coPos,
525 &Written);
526 }
527 else
528 {
529 FillConsoleOutputCharacterA(StdOutput,
530 0xC4, // '-',
531 ListUi->Right - ListUi->Left - 5,
532 coPos,
533 &Written);
534 coPos.X = ListUi->Right - 5;
535 WriteConsoleOutputCharacterA(StdOutput,
536 "(\x18)", // "(up)"
537 3,
538 coPos,
539 &Written);
540 coPos.X = ListUi->Right - 2;
541 FillConsoleOutputCharacterA(StdOutput,
542 0xC4, // '-',
543 2,
544 coPos,
545 &Written);
546 }
547
548 /* Draw upper right corner */
549 coPos.X = ListUi->Right;
550 coPos.Y = ListUi->Top;
551 FillConsoleOutputCharacterA(StdOutput,
552 0xBF, // '+',
553 1,
554 coPos,
555 &Written);
556
557 /* Draw left and right edge */
558 for (i = ListUi->Top + 1; i < ListUi->Bottom; i++)
559 {
560 coPos.X = ListUi->Left;
561 coPos.Y = i;
562 FillConsoleOutputCharacterA(StdOutput,
563 0xB3, // '|',
564 1,
565 coPos,
566 &Written);
567
568 coPos.X = ListUi->Right;
569 FillConsoleOutputCharacterA(StdOutput,
570 0xB3, //'|',
571 1,
572 coPos,
573 &Written);
574 }
575
576 /* Draw lower left corner */
577 coPos.X = ListUi->Left;
578 coPos.Y = ListUi->Bottom;
579 FillConsoleOutputCharacterA(StdOutput,
580 0xC0, // '+',
581 1,
582 coPos,
583 &Written);
584
585 /* Draw lower edge */
586 coPos.X = ListUi->Left + 1;
587 coPos.Y = ListUi->Bottom;
588 if (LastLine - ListUi->Offset <= ListUi->Bottom - ListUi->Top - 2)
589 {
590 FillConsoleOutputCharacterA(StdOutput,
591 0xC4, // '-',
592 ListUi->Right - ListUi->Left - 1,
593 coPos,
594 &Written);
595 }
596 else
597 {
598 FillConsoleOutputCharacterA(StdOutput,
599 0xC4, // '-',
600 ListUi->Right - ListUi->Left - 5,
601 coPos,
602 &Written);
603 coPos.X = ListUi->Right - 5;
604 WriteConsoleOutputCharacterA(StdOutput,
605 "(\x19)", // "(down)"
606 3,
607 coPos,
608 &Written);
609 coPos.X = ListUi->Right - 2;
610 FillConsoleOutputCharacterA(StdOutput,
611 0xC4, // '-',
612 2,
613 coPos,
614 &Written);
615 }
616
617 /* Draw lower right corner */
618 coPos.X = ListUi->Right;
619 coPos.Y = ListUi->Bottom;
620 FillConsoleOutputCharacterA(StdOutput,
621 0xD9, // '+',
622 1,
623 coPos,
624 &Written);
625
626 /* print list entries */
627 ListUi->Line = - ListUi->Offset;
628
629 Entry = List->DiskListHead.Flink;
630 while (Entry != &List->DiskListHead)
631 {
632 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
633
634 /* Print disk entry */
635 PrintDiskData(ListUi, DiskEntry);
636
637 Entry = Entry->Flink;
638 }
639 }
640
641 VOID
642 ScrollDownPartitionList(
643 IN PPARTLIST_UI ListUi)
644 {
645 if (GetNextPartition(ListUi->List))
646 DrawPartitionList(ListUi);
647 }
648
649 VOID
650 ScrollUpPartitionList(
651 IN PPARTLIST_UI ListUi)
652 {
653 if (GetPrevPartition(ListUi->List))
654 DrawPartitionList(ListUi);
655 }
656
657 /* EOF */